﻿#include "RelationMgr.h"
#include "CenterService.h"
#include "Cache/OfflineCharacterDataMgr.h"
#include "Cache/OfflineCharacterData.h"
#include "Active/ActiveCharacter.h"
#include "Active/ActiveCharacterMgr.h"
#include "Common/Utility/ServerTime.h"
#include "base/core/random.h"
#include "Team/TeamManager.h"
#include "ChatCenter/ChatCenter.h"
#include "AccountMgr/CenterAccountMgr.h"
#include "Common/TableData/FriendshipFriendshipCfg.h"
#include "Duplicate/CenterDuplicateMgr.h"

RelationMgr::RelationMgr()
{
	_relationMap.clear();
	_relationPool = new ObjectPool < Relation >;
	m_nStartLoadTime = 0;
	m_bFinishLoad = false;
	m_lastSaveTime = 0;
}

RelationMgr::~RelationMgr()
{
	RelationIter iter = _relationMap.begin();
	while (iter != _relationMap.end()){
		if (nullptr != iter->second)
		{
			_relationPool->FreeObj(iter->second);
			iter->second = nullptr;
		}
		_relationMap.erase(iter++);
	}

	MMO_DELETE(_relationPool);
}

bool RelationMgr::Init()
{
	bool ret = true;
	bool result = false;

	IMessageDispatch *pMessageDispatch = g_GetCenterService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::Init....nullptr == pMessageDispatch ");
		return false;
	}
	pMessageDispatch->registerDBProxyHandler(EMODULE_ID_FRIEND, this);
	pMessageDispatch->registerClientHandler(EMODULE_ID_FRIEND, this);
	pMessageDispatch->registerServerHandler(EMODULE_ID_FRIEND, this);

	g_GetActiveCharacterMgr()->AddCharacterObserver(this);

#ifndef LOAD_RELATION_ONLINE
	ret = g_GetTimerAxis()->SetTimer(TIMER_ID_StartLoad_RealtionData, 2 * 1000, this);
#else
	//每天6点清一下缓存数据
	ret = g_GetTimerAxis()->SetFixTimer(TIMER_ID_Refresh_RealtionData, 15 * 60 * 60, 1, this);
#endif // !LOAD_RELATION_ONLINE

	MMOLOG_PROCESS_ERROR(ret);
	m_lastSaveTime = Time::Now().UnixSec();
	result = true;

Exit0:
	return result;
}

bool RelationMgr::UnInit()
{
	IMessageDispatch *pMessageDispatch = g_GetCenterService()->GetServiceMessageDispatch();
	if (nullptr != pMessageDispatch)
	{
		pMessageDispatch->unregisterDBProxyHandler(EMODULE_ID_FRIEND);
		pMessageDispatch->unregisterClientHandler(EMODULE_ID_FRIEND);
		pMessageDispatch->unregisterServerHandler(EMODULE_ID_FRIEND);
	}

	g_GetActiveCharacterMgr()->RemoveCharacterObserver(this);

	g_GetTimerAxis()->KillAllTimer(this);
	//MMO_DELETE(_relationPool);
	return true;
}

void RelationMgr::ClearCache()
{
	//好友内存数量少于10000条不处理
	if (_relationMap.size() < 10000)
	{
		return;
	}

	LogDebugFmtPrint("[center] RelationMgr::ClearCache _relationMap list size before ClearCache is %d....", _relationMap.size());
	for (RelationIter iter = _relationMap.begin(); iter != _relationMap.end();)
	{
		Relation *pRelation = iter->second;
		if (nullptr != pRelation && !pRelation->IsChange() && pRelation->GetActive() <= 5)
		{
			ActiveCharacter* pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(iter->first);
			if (nullptr == pOnline)
			{
				_relationPool->FreeObj(pRelation);
				pRelation = nullptr;
				_relationMap.erase(iter++);
				continue;
			}
		}
		++iter;
	}
	LogDebugFmtPrint("[center] RelationMgr::ClearCache _relationMap list size after RefreshData is %d....", _relationMap.size());
}

void RelationMgr::IsCreateRelation(CharIDType charId)
{
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charId);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] IsCreateRelation can not find character offline data , charid:%llu ", charId);
		return;
	}

	//2级开放好友系统 这里暂时先硬编码
	/*if (pOffline->GetLevel() >= 1)
	{
		g_GetRelationMgr()->MutRelation(charId);
	}*/
}

void RelationMgr::onCharacterLogin(ActiveCharacter *pOnlineCharacter)
{
	if (nullptr == pOnlineCharacter)	return;
	CharIDType charId = pOnlineCharacter->GetCharID();
	IsCreateRelation(charId);
	//上线先只通知好友列表以及最近联系人列表
	Relation* pRelation = FindRelation(charId);

#ifndef LOAD_RELATION_ONLINE
	if (nullptr == pRelation)
	{
		pRelation = MutRelation(charId);
		if (nullptr == pRelation)
		{
			MMOLOG_FMT_ERROR("[center] RelationMgr::onCharacterLogin nullptr == pRelation...charId:%llu ", charId);
		}
	}
#endif // !LOAD_RELATION_ONLINE

	if (nullptr != pRelation)
	{
		return RelationLogin(pRelation, charId);
	}
	
	if (g_GetCenterService()->IsConnectDBProxy())
	{
		FriendDBRequest req;
		req.set_charid(charId);
		req.add_dstid_lst(charId);
		req.set_operate_type(RELATION_OPERATE_TYPE_LOAD);
		if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_FRIEND_DATA_REQ, &req))
		{
			MMOLOG_FMT_ERROR("[center] RelationMgr::onCharacterLogin SendDataToDBProxy failed...charId:%llu ", charId);
		}
		else
		{
			LogDebugFmtPrint("[center] start login load character relation data....");
		}
	}
	else
	{
		LogErrFmtPrint("RelationMgr::onCharacterLogin...IsConnectDBProxy false...cid:%lu ", charId);
	}
}

void RelationMgr::onCharacterLogout(ActiveCharacter *pOnlineCharacter)
{
	if (nullptr == pOnlineCharacter)	return;
	CharIDType charId = pOnlineCharacter->GetCharID();
	//上线先只通知好友列表以及最近联系人列表
	Relation* pRelation = FindRelation(charId);
	if (nullptr != pRelation)
	{
		WCRealtionOnlineNotify notify;
		notify.set_charid(charId);
		notify.set_isonline(false);

		Relation::GroupList groupList = pRelation->GetGroupList();
		RelationTeam::PlayerList& idList = groupList[GROUP_FRIEND].playerList;
		for (RelationTeam::PlayerListIter iter = idList.begin(); iter != idList.end(); ++iter)
		{
			if (iter->id > 0)
			{
				g_GetCenterService()->SendDataToClient(iter->id, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONLINENOTIFY, &notify);
			}

			//离线删除好友共享刷怪数量
			CharIDType relationCharID = iter->id;
			OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(relationCharID);
			if (nullptr == pOfflineCharacterData)
				continue;

			ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(relationCharID);
			if (nullptr == pActiveCharacter)
				continue;

			Relation* pFriendRelation = FindRelation(relationCharID);
			if (nullptr == pFriendRelation)
				continue;

			iter->killMonsterClonseness = 0;
			RelationTeam &rRelationTeam = pFriendRelation->GetGroupList()[GROUP_FRIEND];
			RelationPlayer *pRelationPlayer = rRelationTeam.GetUser(charId);
			if (pRelationPlayer)
			{
				pRelationPlayer->killMonsterClonseness = 0;
			}
		}

		RelationTeam::PlayerList& hateIdList = groupList[GROUP_HATE].playerList;
		for (RelationTeam::PlayerListIter iter = hateIdList.begin(); iter != hateIdList.end(); ++iter)
		{
			if (iter->id > 0)
			{
				g_GetCenterService()->SendDataToClient(iter->id, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONLINENOTIFY, &notify);
			}
		}

		Relation::RecentList recentList = pRelation->GetRecentList();
		for (Relation::RecentListIter iter = recentList.begin(); iter != recentList.end(); ++iter)
		{
			if (iter->id > 0)
			{
				g_GetCenterService()->SendDataToClient(iter->id, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONLINENOTIFY, &notify);
			}
		}
	}
}

void RelationMgr::onCharacterUpdate(ActiveCharacter *pOnlineCharacter)
{
	if (nullptr == pOnlineCharacter)	return;
	IsCreateRelation(pOnlineCharacter->GetCharID());
}

void RelationMgr::onCharacterDel(OfflineCharacterData *pOffLineCharacter)
{
	if (nullptr == pOffLineCharacter)	return;
	CharIDType charId = pOffLineCharacter->GetCharID();
	//通知DB清除数据库
	DelteFriendDBRequest req;
	req.set_charid(charId);
	if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_DELETE_FRIEND_DATA_NOTIFY, &req))
	{
		LogErrFmtPrint("RelationMgr::onCharacterDel...SendDataToDBProxy failed...cid:%lu ", charId);
	}

	Relation* pRelation = FindRelation(charId);
	if (nullptr != pRelation)
	{
		//回收内存
		_relationMap.erase(charId);
		_relationPool->FreeObj(pRelation);
		pRelation = nullptr;
	}
}

void RelationMgr::onCharacterDisconnect(ActiveCharacter *pOffLineCharacter)
{
	if (nullptr == pOffLineCharacter)	return;
	onCharacterLogout(pOffLineCharacter);
}

void RelationMgr::OnTimer(uint32_t nTimerID)
{
	switch (nTimerID)
	{
	case TIMER_ID_StartLoad_RealtionData:
	{
		if (g_GetCenterService()->IsConnectDBProxy())
		{
			//开始加载离线角色数据
			int32_t offset = 0;
			m_nStartLoadTime = Time::Now().sec();
			AllFriendDBRequest req;
			req.set_offset(offset);
			if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND,DBPROXY_PROTOCOL_ALL_FRIEND_DATA_REQ, &req))
			{
				MMOLOG_FMT_ERROR("[center] LoadRelationDataDBRet SendDataToDBProxy failed...offset:%d ", offset);
			}
			else
			{
				LogDebugFmtPrint("[center] start load all friend data....");
			}

			g_GetTimerAxis()->KillTimer(TIMER_ID_StartLoad_RealtionData, this);
		}
	}
	break;
	case TIMER_ID_Refresh_RealtionData:
	{
		ClearCache();
	}
	break;
	default:
		break;
	}
}

void RelationMgr::onClientMessage(uint32_t actionId, RECV_PACKAGE& package, uint64_t Id /* = 0 */)
{
	UNPACK_MESSAGE_CHAR_ID(package);

	switch (actionId)
	{
	case CLIENT_TO_CENTER_APPLY_RELATION:
	{
		OnApplyRelationReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_AGREE_RELATION:
	{
		OnAgreeRelationReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_DELETE_RELATION:
	{
		OnDeleteRelationReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_RECENT_CHAT_LIST:
	{
		OnRecentChatListReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_ONEKEY_FRIEND:
	{
		OnOneKeyFriendReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_RELATION_INFO:
	{
		OnRelationInfoReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_SEARCH_USER:
	{
		OnSearchUserReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_GIVE_PHYSCIAL:
	{
		OnGivePhysicalReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_AllGIVE_PHYSICAL:
	{
		OnAllGivePhysicalReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_GET_PHYSICAL:
	{
		OnGetPhysicalReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_GET_PHYSICAL_GIFT:
	{
		OnGetPhysicalGiftReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_APPLYLIST:
	{
		OnApplyListReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_CLEARAPPLYLIST:
	{
		OnClearApplyListReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_ONEKEYAGREERELATION:
	{
		OnOneKeyAgreeRelationReq(charId, package);
		break;
	}
	case CLIENT_TO_CENTER_ADDRECENTLIST:
	{
		OnAddRecentListReq(charId, package);
		break;
	}
	case CLIENT_TO_SERVER_HANDSEL_ROSE:
	{
		OnHandselRoseReq(charId, package);
		break;
	}
	default:
		break;
	}
}

ProtoBuf::ERetCode RelationMgr::OperateCheck(CharIDType &operateID, CharIDType dstID)
{
	OfflineCharacterData *pOperateIDOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(operateID);
	if (nullptr == pOperateIDOfflineCharacterData)
	{
		return RET_NOT_HAVE_CHARACTER;
	}

	Relation* pOperateIDRelation = FindRelation(operateID);
	if (nullptr == pOperateIDRelation)
	{
		return RET_FAIL;
	}

	if (dstID <= 0)
	{
		return RET_SUCCESS;
	}

	OfflineCharacterData *pDstIDOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(dstID);
	if (nullptr == pDstIDOfflineCharacterData)
	{
		return RET_NOT_HAVE_CHARACTER;
	}

	Relation* pDstIDRelation = FindRelation(dstID);
	if (nullptr == pDstIDRelation)
	{
		return RET_RELATION_HAVE_NO_DATA;
	}

	return RET_SUCCESS;
}

void RelationMgr::QueryRelationDB(CharIDType &operateID, CharIDType &dstID, RELATION_OPERATE_TYPE type, string data)
{
	if (!g_GetCenterService()->IsConnectDBProxy())
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::QueryRelationDB connect db failed...operateID:%llu, dstID:%llu, type:%d", operateID, dstID, type);
		return;
	}

	FriendDBRequest req;
	req.set_charid(operateID);
	req.add_dstid_lst(dstID);
	req.set_operate_type(type);
	req.set_data(data);
	if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_FRIEND_DATA_REQ, &req))
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::QueryRelationDB SendDataToDBProxy failed...operateID:%llu, dstID:%llu, type:%d", operateID, dstID, type);
	}
	else
	{
		LogDebugFmtPrint("[center] RelationMgr::QueryRelationDB load character relation data....operateID:%llu, dstID:%llu, type:%d", operateID, dstID, type);
	}
}

void RelationMgr::QueryRelationDBEx(CharIDType &operateID, VEC_UINT64 &list, RELATION_OPERATE_TYPE type, string data)
{
	if (!g_GetCenterService()->IsConnectDBProxy())
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::QueryRelationDBEx connect db failed...operateID:%llu, dstID_size():%d, type:%d", operateID, list.size(), type);
		return;
	}

	FriendDBRequest req;
	req.set_charid(operateID);
	for (size_t i = 0; i != list.size(); ++i)
	{
		req.add_dstid_lst(list.at(i));
	}
	req.set_operate_type(type);
	req.set_data(data);
	if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_FRIEND_DATA_REQ, &req))
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::QueryRelationDBEx SendDataToDBProxy failed...operateID:%llu, type:%d", operateID, type);
	}
	else
	{
		LogDebugFmtPrint("[center] RelationMgr::QueryRelationDBEx load character relation data....operateID:%llu, type:%d", operateID, type);
	}
}

void RelationMgr::RelationLogin(Relation *pRelation, CharIDType &charId)
{
	WCRealtionOnlineNotify notify;
	notify.set_charid(charId);
	notify.set_isonline(true);
	Relation::GroupList groupList = pRelation->GetGroupList();
	RelationTeam::PlayerList& idList = groupList[GROUP_FRIEND].playerList;
	for (RelationTeam::PlayerListIter iter = idList.begin(); iter != idList.end(); ++iter)
	{
		if (iter->id > 0)
		{
			g_GetCenterService()->SendDataToClient(iter->id, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONLINENOTIFY, &notify);
		}
	}

	RelationTeam::PlayerList& hateIdList = groupList[GROUP_HATE].playerList;
	for (RelationTeam::PlayerListIter iter = hateIdList.begin(); iter != hateIdList.end(); ++iter)
	{
		if (iter->id > 0)
		{
			g_GetCenterService()->SendDataToClient(iter->id, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONLINENOTIFY, &notify);
		}
	}

	Relation::RecentList recentList = pRelation->GetRecentList();
	for (Relation::RecentListIter iter = recentList.begin(); iter != recentList.end(); ++iter)
	{
		if (iter->id > 0)
		{
			g_GetCenterService()->SendDataToClient(iter->id, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONLINENOTIFY, &notify);
		}
	}

	//离线时加的好友计入逻辑服统计
	if (pRelation->GetFriendsAdd() > 0)
	{
		NotifyLogicAddFriend(charId, pRelation->GetFriendsAdd());
		pRelation->SetFriendsAdd(0);
	}
}

bool RelationMgr::HandlleApplyRelationReq(CharIDType applyID, ProtoBuf::CWApplyRelationReq &req)
{
	CharIDType applyedID = req.playerid(); //被申请方的玩家ID
	uint32_t gourpIndex = req.groupindex();
	if (gourpIndex == GROUP_FRIEND) //添加好友
	{
		ProtoBuf::ERetCode ret = ApplyAddFrined(applyID, applyedID);
		ProtoBuf::WCApplyRelationRsp addRelationRsp;
		addRelationRsp.set_ret(ret);
		addRelationRsp.set_playerid(applyedID);
		g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_APPLY_RELATION, &addRelationRsp);

		if (ret == RET_SUCCESS)
		{
			//如果申请方摘要数据没有了则为出错
			OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
			if (nullptr == pOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] HandlleApplyRelationReq but OfflineCharacterData is nullptr,charID:%llu ", applyID);
				return false;
			}

			Relation* pRelation = FindRelation(applyID);
			if (nullptr == pRelation)
			{
				MMOLOG_FMT_ERROR("[center] HandlleApplyRelationReq but applyID pRelation is nullptr,applyID:%u ", applyID);
				return false;
			}

			//发送通知消息给被申请方
			ProtoBuf::WCNotifyRelationRsp notify;
			notify.set_ret(RET_SUCCESS);
			notify.set_flag(RELATION_APPLY);
			notify.set_groupindex(gourpIndex);
			ProtoBuf::CharacterPlayerMiniInfo* applyInfo = notify.mutable_friendinfo();
			if (nullptr != applyInfo)
			{
				applyInfo->set_playerid(applyID);
				applyInfo->set_playername(pOfflineCharacterData->GetCharName());
				applyInfo->set_sex(pOfflineCharacterData->GetSex());
				applyInfo->set_level(pOfflineCharacterData->GetLevel());
				applyInfo->set_prof(pOfflineCharacterData->GetProf());
				applyInfo->set_fightpower(pOfflineCharacterData->GetFight());
				applyInfo->set_camp(pOfflineCharacterData->GetCampID());
			}
			else
			{
				LogErrFmtPrint("HandlleApplyRelationReq...nullptr == applyInfo applyID:%lu,applyedID:%lu,gourpIndex:%d ", applyID, applyedID, gourpIndex);
			}
			
			g_GetCenterService()->SendDataToClient(applyedID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notify);
		}
	}
	else if (gourpIndex == GROUP_BLACK) //添加黑名单
	{
		ProtoBuf::ERetCode ret = AddRelation(gourpIndex, applyID, applyedID);
		ProtoBuf::WCApplyRelationRsp addRelationRsp;
		addRelationRsp.set_ret(ret);
		g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_APPLY_RELATION, &addRelationRsp);

		if (ret == RET_SUCCESS)
		{
			//如果黑名单一方摘要数据没有了则为出错
			OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyedID);
			if (nullptr == pOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] HandlleApplyRelationReq add black but OfflineCharacterData is nullptr,applyedID:%llu ", applyedID);
				return false;
			}

			//将黑名单的信息发送给添加方
			ProtoBuf::WCNotifyRelationRsp notify;
			notify.set_ret(RET_SUCCESS);
			notify.set_flag(RELATION_PASS);
			notify.set_agree(true);
			notify.set_groupindex(gourpIndex);
			ProtoBuf::CharacterPlayerMiniInfo* applyedInfo = notify.mutable_friendinfo();
			if (nullptr != applyedInfo)
			{
				applyedInfo->set_playerid(applyedID);
				applyedInfo->set_playername(pOfflineCharacterData->GetCharName());
				applyedInfo->set_sex(pOfflineCharacterData->GetSex());
				applyedInfo->set_level(pOfflineCharacterData->GetLevel());
				applyedInfo->set_prof(pOfflineCharacterData->GetProf());
				applyedInfo->set_fightpower(pOfflineCharacterData->GetFight());
				applyedInfo->set_camp(pOfflineCharacterData->GetCampID());
			}
			else
			{
				LogErrFmtPrint("HandlleApplyRelationReq...nullptr == applyedInfo applyID:%lu,applyedID:%lu,gourpIndex:%d ", applyID, applyedID, gourpIndex);
			}
			
			g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notify);

			//将添加方的信息发送给被添加为黑名单的玩家
			notify.Clear();
			notify.set_ret(RET_SUCCESS);
			notify.set_flag(RELATION_DELETE);
			ProtoBuf::CharacterPlayerMiniInfo* applyInfo = notify.mutable_friendinfo();
			applyInfo->set_playerid(applyID);
			g_GetCenterService()->SendDataToClient(applyedID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notify);
		}

	}

	return true;
}

bool RelationMgr::HandleAgreeRelationReq(CharIDType agreeID, ProtoBuf::CWAgreeRelationReq &req)
{
	uint32_t groupIndex = req.groupindex();
	if (groupIndex != GROUP_FRIEND)	//非好友组
	{
		ProtoBuf::WCAgreeRelationRsp agreeRelationRsp;
		agreeRelationRsp.set_ret(RET_RELATION_APPLY_GROUP_ERROR);
		g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_AGREE_RELATION, &agreeRelationRsp);
		return false;
	}

	CharIDType applyID = req.playerid(); //申请方的玩家ID
	if (req.agree()) //同意
	{
		ProtoBuf::ERetCode ret = AddRelation(groupIndex, agreeID, applyID);
		if (ret != RET_SUCCESS)
		{
			ProtoBuf::WCAgreeRelationRsp agreeRelationRsp;
			agreeRelationRsp.set_ret(ret);
			agreeRelationRsp.set_playerid(applyID);
			g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_AGREE_RELATION, &agreeRelationRsp);
			return false;
		}
		else
		{
			OfflineCharacterData *pAgreeOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(agreeID);
			if (nullptr == pAgreeOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] HandleAgreeRelationReq 11 but argeeID OfflineCharacterData is nullptr,agreeID:%llu ", agreeID);
				return false;
			}

			OfflineCharacterData *pApplyOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
			if (nullptr == pApplyOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] HandleAgreeRelationReq 22 but applyID OfflineCharacterData is nullptr,applyID:%llu ", applyID);
				return false;
			}

			Relation* pAgreeRelation = FindRelation(agreeID);
			if (nullptr == pAgreeRelation)
			{
				MMOLOG_FMT_ERROR("[center] HandleAgreeRelationReq 33 but agreeID pRelation is nullptr,agreeID:%u ", agreeID);
				return false;
			}

			Relation* pApplyRelation = FindRelation(applyID);
			if (nullptr == pApplyRelation)
			{
				MMOLOG_FMT_ERROR("[center] HandleAgreeRelationReq 44 but applyID pRelation is nullptr,applyID:%u ", applyID);
				return false;
			}

			uint64_t nowTime = Time::Now().UnixSec();

			//将同意方的信息内容同步给申请方
			ProtoBuf::WCNotifyRelationRsp notifyRelationRsp;
			notifyRelationRsp.set_ret(RET_SUCCESS);
			notifyRelationRsp.set_flag(RELATION_PASSIVE_PASS);
			notifyRelationRsp.set_agree(true);
			notifyRelationRsp.set_groupindex(groupIndex);
			ProtoBuf::CharacterPlayerMiniInfo* agreeInfo = notifyRelationRsp.mutable_friendinfo();
			if (nullptr == agreeInfo)
			{
				LogErrFmtPrint("HandleAgreeRelationReq...nullptr == agreeInfo, agreeID:%lu,applyID:%lu ", agreeID, applyID);
				return false;
			}
			agreeInfo->set_playerid(agreeID);
			agreeInfo->set_playername(pAgreeOfflineCharacterData->GetCharName());
			agreeInfo->set_sex(pAgreeOfflineCharacterData->GetSex());
			agreeInfo->set_level(pAgreeOfflineCharacterData->GetLevel());
			agreeInfo->set_prof(pAgreeOfflineCharacterData->GetProf());
			agreeInfo->set_fightpower(pAgreeOfflineCharacterData->GetFight());
			agreeInfo->set_camp(pAgreeOfflineCharacterData->GetCampID());
			
			//判断之前是否已经赠送过体力了
			FriendPhysicalTab* pAgreeFriendPhyTab = pApplyRelation->GetFriendPhysicalTab(agreeID);
			if (nullptr != pAgreeFriendPhyTab)
			{
				if (Time::GetLocalDayDifference(pAgreeFriendPhyTab->lastGivePlyTime, nowTime) == 0)
				{
					agreeInfo->set_giveplysical(true);
				}
				if (Time::GetLocalDayDifference(pAgreeFriendPhyTab->lastGetPhyTime, nowTime) == 0)
				{
					agreeInfo->set_getplystatus(pAgreeFriendPhyTab->getPlyStatus);
				}
			}

			//判断是否在线
			ActiveCharacter* pAgreeActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(agreeID);
			if (nullptr != pAgreeActiveCharacter)
			{
				agreeInfo->set_online(true);
			}

			//判断是否组队
			if (g_GetTeamMgr()->GetTeamId(agreeID) > 0)
			{
				agreeInfo->set_inteam(true);
			}

			g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notifyRelationRsp);

			notifyRelationRsp.Clear();
			//将申请方的信息内容同步给同意方
			notifyRelationRsp.set_ret(RET_SUCCESS);
			notifyRelationRsp.set_flag(RELATION_PASS);
			notifyRelationRsp.set_agree(true);
			notifyRelationRsp.set_groupindex(groupIndex);
			ProtoBuf::CharacterPlayerMiniInfo* applyInfo = notifyRelationRsp.mutable_friendinfo();
			if (nullptr == applyInfo)
			{
				LogErrFmtPrint("HandleAgreeRelationReq...nullptr == applyInfo, agreeID:%lu,applyID:%lu,groupIndex:%d ", agreeID, applyID, groupIndex);
				return false;
			}
			applyInfo->set_playerid(applyID);
			applyInfo->set_playername(pApplyOfflineCharacterData->GetCharName());
			applyInfo->set_sex(pApplyOfflineCharacterData->GetSex());
			applyInfo->set_level(pApplyOfflineCharacterData->GetLevel());
			applyInfo->set_prof(pApplyOfflineCharacterData->GetProf());
			applyInfo->set_fightpower(pApplyOfflineCharacterData->GetFight());
			applyInfo->set_camp(pApplyOfflineCharacterData->GetCampID());
			
			//判断之前是否已经赠送过体力了
			FriendPhysicalTab* pApplyFriendPhyTab = pAgreeRelation->GetFriendPhysicalTab(applyID);
			if (nullptr != pApplyFriendPhyTab)
			{
				if (Time::GetLocalDayDifference(pApplyFriendPhyTab->lastGivePlyTime, nowTime) == 0)
				{
					applyInfo->set_giveplysical(true);
				}
				if (Time::GetLocalDayDifference(pApplyFriendPhyTab->lastGetPhyTime, nowTime) == 0)
				{
					applyInfo->set_getplystatus(pApplyFriendPhyTab->getPlyStatus);
				}
			}

			//判断是否在线
			ActiveCharacter* pApplyActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(applyID);
			if (nullptr != pApplyActiveCharacter)
			{
				applyInfo->set_online(true);
			}

			//判断是否组队
			if (g_GetTeamMgr()->GetTeamId(applyID) > 0)
			{
				applyInfo->set_inteam(true);
			}

			g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notifyRelationRsp);
		}
	}
	else
	{
		ProtoBuf::ERetCode ret = NoArgeeRelation(groupIndex, agreeID, applyID);
		ProtoBuf::WCAgreeRelationRsp agreeRelationRsp;
		agreeRelationRsp.set_ret(ret);
		agreeRelationRsp.set_playerid(applyID);
		g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_AGREE_RELATION, &agreeRelationRsp);

		if (ret == RET_SUCCESS)
		{
			//不同意
			OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(agreeID);
			if (nullptr == pOffline)
			{
				MMOLOG_FMT_ERROR("[center] HandleAgreeRelationReq 55 can not find agreeID offline data , agreeID:%llu ", agreeID);
				return false;
			}

			ProtoBuf::WCNotifyRelationRsp notifyRelationRsp;
			notifyRelationRsp.set_ret(RET_RELATION_NOT_AGREE);
			notifyRelationRsp.set_flag(RELATION_PASS);
			notifyRelationRsp.set_agree(false);
			ProtoBuf::CharacterPlayerMiniInfo* applyInfo = notifyRelationRsp.mutable_friendinfo();
			if (nullptr == applyInfo)
			{
				LogErrFmtPrint("HandleAgreeRelationReq11...nullptr == applyInfo, agreeID:%lu,applyID:%lu,groupIndex:%d ", agreeID, applyID, groupIndex);
				return false;
			}
			applyInfo->set_playerid(agreeID);
			applyInfo->set_playername(pOffline->GetCharName());
			
			g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notifyRelationRsp);
		}
	}
	return true;
}

bool RelationMgr::HandleOneKeyAgreeRelationReq(CharIDType agreeID, ProtoBuf::CWOneKeyAgreeRelationReq &req)
{
	Relation* pAgreeRelation = g_GetRelationMgr()->FindRelation(agreeID);
	if (nullptr == pAgreeRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::HandleOneKeyAgreeRelationReq but agreeID pRelation is nullptr,agreeID:%u ", agreeID);
		return false;
	}

	ProtoBuf::ERetCode ret = RET_SUCCESS;
	ProtoBuf::WCOneKeyAgreeRelationRsp oneKeyAgreeRelationRsp;

	Relation::ApplyIDList applyIdList = pAgreeRelation->GetApplyIDList();
	for (Relation::ApplyIDListpIter iter = applyIdList.begin(); iter != applyIdList.end(); ++iter)
	{
		CharIDType applyID = *iter;
		ret = AddRelation(GROUP_FRIEND, agreeID, applyID);

		//这种情况下直接退出循环了
		if (ret == RET_RELATION_SIZE_LIMIT_NO_ADD)
		{
			oneKeyAgreeRelationRsp.set_ret(ret);
			g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONEKEYAGREERELATION, &oneKeyAgreeRelationRsp);
			break;
		}

		if (ret == RET_RELATION_SIZE_LIMIT_NO_ADD_OTHER)
		{
			oneKeyAgreeRelationRsp.set_ret(ret);
			g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONEKEYAGREERELATION, &oneKeyAgreeRelationRsp);
			continue;
		}

		//这种情况认为添加成功
		if (ret == RET_SUCCESS)
		{
			Relation* pAgreeRelation = FindRelation(agreeID);
			if (nullptr == pAgreeRelation)
			{
				MMOLOG_FMT_ERROR("[center] HandleOneKeyAgreeRelationReq 11 but agreeID pRelation is nullptr,agreeID:%u ", agreeID);
				continue;
			}

			Relation* pApplyRelation = FindRelation(applyID);
			if (nullptr == pApplyRelation)
			{
				MMOLOG_FMT_ERROR("[center] HandleOneKeyAgreeRelationReq 22 but applyID pRelation is nullptr,applyID:%u ", applyID);
				continue;
			}

			ProtoBuf::WCNotifyRelationRsp notifyRelationRsp;

			OfflineCharacterData *pAgreeOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(agreeID);
			if (nullptr == pAgreeOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] HandleOneKeyAgreeRelationReq 33 but argeeID OfflineCharacterData is nullptr,agreeID:%llu ", agreeID);
				return false;
			}

			OfflineCharacterData *pApplyOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
			if (nullptr == pApplyOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] HandleOneKeyAgreeRelationReq 44 but applyID OfflineCharacterData is nullptr,applyID:%llu ", applyID);
				return false;
			}

			uint64_t nowTime = Time::Now().UnixSec();

			//将同意方的信息内容同步给申请方
			notifyRelationRsp.set_ret(RET_SUCCESS);
			notifyRelationRsp.set_flag(RELATION_PASSIVE_PASS);
			notifyRelationRsp.set_agree(true);
			notifyRelationRsp.set_groupindex(GROUP_FRIEND);
			ProtoBuf::CharacterPlayerMiniInfo* agreeInfo = notifyRelationRsp.mutable_friendinfo();
			if (nullptr == agreeInfo)
			{
				LogErrFmtPrint("HandleOneKeyAgreeRelationReq..nullptr == agreeInfo..applyID:%lu,agreeID:%lu ", applyID, agreeID);
				return false;
			}
			agreeInfo->set_playerid(agreeID);
			agreeInfo->set_playername(pAgreeOfflineCharacterData->GetCharName());
			agreeInfo->set_sex(pAgreeOfflineCharacterData->GetSex());
			agreeInfo->set_level(pAgreeOfflineCharacterData->GetLevel());
			agreeInfo->set_prof(pAgreeOfflineCharacterData->GetProf());
			agreeInfo->set_fightpower(pAgreeOfflineCharacterData->GetFight());
			agreeInfo->set_camp(pAgreeOfflineCharacterData->GetCampID());
			//判断之前是否已经赠送过体力了
			FriendPhysicalTab* pAgreeFriendPhyTab = pApplyRelation->GetFriendPhysicalTab(agreeID);
			if (nullptr != pAgreeFriendPhyTab)
			{
				if (Time::GetLocalDayDifference(pAgreeFriendPhyTab->lastGivePlyTime, nowTime) == 0)
				{
					agreeInfo->set_giveplysical(true);
				}
				if (Time::GetLocalDayDifference(pAgreeFriendPhyTab->lastGetPhyTime, nowTime) == 0)
				{
					agreeInfo->set_getplystatus(pAgreeFriendPhyTab->getPlyStatus);
				}
			}

			//判断是否在线
			ActiveCharacter* pAgreeActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(agreeID);
			if (nullptr != pAgreeActiveCharacter)
			{
				agreeInfo->set_online(true);
			}

			//判断是否组队
			if (g_GetTeamMgr()->GetTeamId(agreeID) > 0)
			{
				agreeInfo->set_inteam(true);
			}

			g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notifyRelationRsp);

			notifyRelationRsp.Clear();
			//将申请方的信息内容同步给同意方
			notifyRelationRsp.set_ret(RET_SUCCESS);
			notifyRelationRsp.set_flag(RELATION_PASS);
			notifyRelationRsp.set_agree(true);
			notifyRelationRsp.set_groupindex(GROUP_FRIEND);
			ProtoBuf::CharacterPlayerMiniInfo* applyInfo = notifyRelationRsp.mutable_friendinfo();
			if (nullptr == applyInfo)
			{
				LogErrFmtPrint("HandleOneKeyAgreeRelationReq66...nullptr == applyInfo..applyID:%lu,agreeID:%lu ", applyID, agreeID);
				return false;
			}
			applyInfo->set_playerid(applyID);
			applyInfo->set_playername(pApplyOfflineCharacterData->GetCharName());
			applyInfo->set_sex(pApplyOfflineCharacterData->GetSex());
			applyInfo->set_level(pApplyOfflineCharacterData->GetLevel());
			applyInfo->set_prof(pApplyOfflineCharacterData->GetProf());
			applyInfo->set_fightpower(pApplyOfflineCharacterData->GetFight());
			applyInfo->set_camp(pApplyOfflineCharacterData->GetCampID());
			//判断之前是否已经赠送过体力了
			FriendPhysicalTab* pApplyFriendPhyTab = pAgreeRelation->GetFriendPhysicalTab(applyID);
			if (nullptr != pApplyFriendPhyTab)
			{
				if (Time::GetLocalDayDifference(pApplyFriendPhyTab->lastGivePlyTime, nowTime) == 0)
				{
					applyInfo->set_giveplysical(true);
				}
				if (Time::GetLocalDayDifference(pApplyFriendPhyTab->lastGetPhyTime, nowTime) == 0)
				{
					applyInfo->set_getplystatus(pApplyFriendPhyTab->getPlyStatus);
				}
			}

			//判断是否在线
			ActiveCharacter* pApplyActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(applyID);
			if (nullptr != pApplyActiveCharacter)
			{
				applyInfo->set_online(true);
			}

			//判断是否组队
			if (g_GetTeamMgr()->GetTeamId(applyID) > 0)
			{
				applyInfo->set_inteam(true);
			}

			g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notifyRelationRsp);
		}
	}

	return true;
}

bool RelationMgr::HandleDeleteRelationReq(CharIDType operateID, ProtoBuf::CWDeleteRelationReq &req)
{
	uint32_t groupIndex = req.groupindex();
	std::vector<CharIDType> sucessVec;
	ProtoBuf::CWDeleteRelationRsp toOperatorRsp;
	for (int i = 0; i < req.playeridlist_size(); i++)
	{
		CharIDType deleteID = req.playeridlist(i);
		ProtoBuf::ERetCode ret = DeleteRelation(groupIndex, operateID, deleteID);
		if (ret == RET_SUCCESS)
		{
			if (groupIndex == GROUP_FRIEND)
			{
				ProtoBuf::CWDeleteRelationRsp toDeleteRsp;
				toDeleteRsp.set_groupindex(groupIndex);
				toDeleteRsp.set_ret(RET_SUCCESS);
				toDeleteRsp.add_playerid(operateID);
				toDeleteRsp.set_isactive(false);
				g_GetCenterService()->SendDataToClient(deleteID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_DELETE_RELATION, &toDeleteRsp);
			}
			toOperatorRsp.add_playerid(deleteID);
		}
	}

	toOperatorRsp.set_groupindex(groupIndex);
	toOperatorRsp.set_ret(RET_SUCCESS);
	toOperatorRsp.set_isactive(true);
	g_GetCenterService()->SendDataToClient(operateID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_DELETE_RELATION, &toOperatorRsp);
	return true;
}

bool RelationMgr::HandleRelationInfoReq(CharIDType charID, ProtoBuf::CWRelationInfoReq &req)
{
	ProtoBuf::WCRelationInfoRsp relationInfoRsp;

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("[center] HandleRelationInfoReq nullptr == pRelation,CharID:%llu ", charID);
		return true;
	}

	uint32_t groupIndex = req.groupindex();
	if (groupIndex < GROUP_FRIEND || groupIndex > GROUP_HATE)
	{
		MMOLOG_FMT_ERROR("[center] HandleRelationInfoReq but groupIndex is error,CharID:%llu, groupIndex:%d ", charID, groupIndex);
		return false;
	}

	VEC_UINT64 deleteIds;
	Relation::GroupList groupList = pRelation->GetGroupList();
	ProtoBuf::GroupRelationInfo* groupRelationInfo = relationInfoRsp.add_relationinfo();
	RelationTeam::PlayerList& idList = groupList[groupIndex].playerList;

	for (RelationTeam::PlayerListIter iter = idList.begin(); iter != idList.end(); ++iter)
	{
		CharIDType relationCharID = iter->id;
		OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(relationCharID);
		//角色不存在了
		if (nullptr == pOfflineCharacterData)
		{
			deleteIds.push_back(relationCharID);
			continue;
		}

		if (groupIndex == GROUP_FRIEND)
		{
			//对方在我的好友列表 我却不在对方的好友列表
			Relation* pFRelation = FindRelation(relationCharID);
			if (nullptr == pFRelation || !pRelation->IsMyfriend(relationCharID) || !pFRelation->IsMyfriend(charID))
			{
				deleteIds.push_back(relationCharID);
				continue;
			}
		}

		ProtoBuf::CharacterPlayerMiniInfo* miniInfo = groupRelationInfo->add_relationinfolist();
		if (nullptr == miniInfo)
		{
			LogErrFmtPrint("RelationMgr::HandleRelationInfoReq...nullptr == miniInfo...cid:%lu,relationCharID:%lu", charID, relationCharID);
			return false;
		}
		miniInfo->set_playerid(relationCharID);
		miniInfo->set_playername(pOfflineCharacterData->GetCharName());
		miniInfo->set_sex(pOfflineCharacterData->GetSex());
		miniInfo->set_level(pOfflineCharacterData->GetLevel());
		miniInfo->set_prof(pOfflineCharacterData->GetProf());
		miniInfo->set_camp(pOfflineCharacterData->GetCampID());
		miniInfo->set_fightpower(pOfflineCharacterData->GetFight());
		miniInfo->set_killmetimes(iter->killMeTimes);	

		//好友关系需要判断一下体力信息
		if (groupIndex == GROUP_FRIEND)
		{
			uint64_t nowTime = Time::Now().UnixSec();
			FriendPhysicalTab* pFriendPhyTab = pRelation->GetFriendPhysicalTab(relationCharID);
			if (nullptr != pFriendPhyTab)
			{
				if (Time::GetLocalDayDifference(pFriendPhyTab->lastGivePlyTime, nowTime) == 0)
				{
					miniInfo->set_giveplysical(true);
				}
				if (Time::GetLocalDayDifference(pFriendPhyTab->lastGetPhyTime, nowTime) == 0)
				{
					miniInfo->set_getplystatus(pFriendPhyTab->getPlyStatus);
				}
				if (miniInfo->getplystatus() == 2)	// 已经领取过体力 前端需要制作领取列表
				{
					miniInfo->set_getplytime(pFriendPhyTab->lastGetPhyTime);
				}
			}

			//是否领取过体力
			FriendGetPhysicalTab* pGetFriendPhyTab = pRelation->GetFriendGetPhysicalTab(relationCharID);
			if (nullptr != pGetFriendPhyTab)
			{
				if (Time::GetLocalDayDifference(pGetFriendPhyTab->getPlyTime, nowTime) == 0)
				{
					//同一天
					miniInfo->set_plygeted(true);
					miniInfo->set_getplytime(pGetFriendPhyTab->getPlyTime);
				}
				else
				{
					pRelation->DelFriendGetPhysicalTab(relationCharID);
				}
			}
			//好友增加亲密度信息
			miniInfo->set_closeness(pRelation->GetCloseness(relationCharID));
		}

		//判断是否在线
		ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(relationCharID);
		if (nullptr != pActiveCharacter)
		{
			miniInfo->set_online(true);
		}

		//判断是否组队
		if (g_GetTeamMgr()->GetTeamId(relationCharID) > 0)
		{
			miniInfo->set_inteam(true);
		}
	}

	relationInfoRsp.set_groupindex(groupIndex);
	relationInfoRsp.set_leftgivetimes(pRelation->GetLeftGiveTimes());
	relationInfoRsp.set_giftprogress(pRelation->GetGiftProgress());

	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_RELATION_INFO, &relationInfoRsp);

	//最后做一下清除工作
	for (uint32_t i = 0; i < deleteIds.size(); i++)
	{
		pRelation->DelUser(groupIndex, deleteIds[i]);
		//pRelation->DeleteApply(deleteIds[i]);	//删除一下申请列表
		pRelation->DelFriendPhysicalTab(deleteIds[i]); //删除体力标记
	}

	return true;
}

bool RelationMgr::HandleGivePhysicalReq(CharIDType charID, ProtoBuf::CWGivePhyscialReq &req)
{
	ProtoBuf::WCGivePhyscialRsp givePhyscialRsp;
	CharIDType dstID = req.playerid();

	ERetCode status = GivePhyscial(charID, dstID);
	givePhyscialRsp.set_ret(status);
	givePhyscialRsp.set_playerid(dstID);
	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_GIVE_PHYSICAL, &givePhyscialRsp);

	if (status == RET_SUCCESS)
	{
		ProtoBuf::WCPhysicalNotifyRsp notify;
		notify.set_type(RELATION_PHYSICAL_GIVE);
		notify.set_playerid(charID);
		g_GetCenterService()->SendDataToClient(dstID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_PHYSICALNOTIFY, &notify);

		//通知逻辑服
		uint32_t logicId = g_GetCenterAccountMgr()->GetLogicIdByCid(charID);
		ProtoBuf::WLPhysicalNotify notifyLogic;
		notifyLogic.set_times(1);
		notifyLogic.set_playerid(charID);
		g_GetCenterService()->SendDataToLogic(logicId, EMODULE_ID_FRIEND, CEENER_SERVER_PROTOCOL_GIVE_PHYSICAL_GIFT, &notifyLogic);
	}

	return true;
}

bool RelationMgr::HandleAllGivePhysicalReq(CharIDType charID, ProtoBuf::CWAllGivePhyscialReq &req)
{
	ProtoBuf::WCAllGivePhyscialRsp allGivePhyscialRsp;
	uint32_t times = 0;
	for (int i = 0; i < req.playerids_size(); i++)
	{
		CharIDType dstID = req.playerids(i);
		ERetCode ret = GivePhyscial(charID, dstID);

		if (ret == RET_SUCCESS)
		{
			allGivePhyscialRsp.add_playerids(dstID);

			ProtoBuf::WCPhysicalNotifyRsp notify;
			notify.set_type(RELATION_PHYSICAL_GIVE);
			notify.set_playerid(charID);
			g_GetCenterService()->SendDataToClient(dstID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_PHYSICALNOTIFY, &notify);
			times++;
		}
	}

	//通知逻辑服
	if (times > 0)
	{
		uint32_t logicId = g_GetCenterAccountMgr()->GetLogicIdByCid(charID);
		ProtoBuf::WLPhysicalNotify notifyLogic;
		notifyLogic.set_times(times);
		notifyLogic.set_playerid(charID);
		g_GetCenterService()->SendDataToLogic(logicId, EMODULE_ID_FRIEND, CEENER_SERVER_PROTOCOL_GIVE_PHYSICAL_GIFT, &notifyLogic);
	}

	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_AllGIVE_PHYSICAL, &allGivePhyscialRsp);
	return true;
}

bool RelationMgr::HandleGetPhysicalReq(CharIDType srcID, ProtoBuf::CWGetPhyscialReq &req)
{
	CharIDType dstID = req.playerid();
	ERetCode status = GetPhyscial(srcID, dstID);
	ProtoBuf::WCGetPhyscialRsp getPhyscialRsp;
	getPhyscialRsp.set_ret(status);
	getPhyscialRsp.set_playerid(dstID);
	g_GetCenterService()->SendDataToClient(srcID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_GET_PHYSICAL, &getPhyscialRsp);

	if (status == RET_SUCCESS)
	{
		ProtoBuf::WCPhysicalNotifyRsp notify;
		notify.set_type(RELATION_PHYSICAL_GET);
		notify.set_playerid(srcID);
		g_GetCenterService()->SendDataToClient(dstID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_PHYSICALNOTIFY, &notify);

		ProtoBuf::WLGetPhyscialReq req;
		req.set_playerid(srcID);
		g_GetCenterService()->SendDataToLogicByCharID(srcID, EMODULE_ID_FRIEND, CENTER_SERVER_PROTOCOL_GET_PHYSICAL_TO_LOGIC, &req);
	}

	return true;
}

bool RelationMgr::HandleHandselRoseReq(CharIDType charID, ProtoBuf::HandselRoseReq &req)
{
	CharIDType dstID = req.dst_char_id();
	ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(dstID);
	if (nullptr == pActiveCharacter)
	{
		ProtoBuf::HandselRoseRsp handselRoseRsp;
		handselRoseRsp.set_ret(RET_PLAYER_NOT_ONLINE);
		g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_HANDSEL_ROSE, &handselRoseRsp);
		return false;
	}

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::HandleHandselRoseReq nullptr == pRelation failed...charId:%llu ", charID);
		return false;
	}

	Relation* pDstRelation = FindRelation(dstID);
	if (nullptr == pDstRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::HandleHandselRoseReq nullptr == pDstRelation failed...charId:%llu ", charID);
		return false;
	}

	if (!pRelation->IsMyfriend(dstID) || !pDstRelation->IsMyfriend(charID))
	{
		ProtoBuf::HandselRoseRsp handselRoseRsp;
		handselRoseRsp.set_ret(RET_RELATION_NOT_FRIENDS);
		g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_HANDSEL_ROSE, &handselRoseRsp);
		return false;
	}

	C2LHandselRoseReq c2lhandselRoseReq;
	c2lhandselRoseReq.set_type(req.type());
	c2lhandselRoseReq.set_charid(charID);
	c2lhandselRoseReq.set_item_id(req.item_id());
	c2lhandselRoseReq.set_item_count(req.item_count());
	c2lhandselRoseReq.set_dst_char_id(req.dst_char_id());
	g_GetCenterService()->SendDataToLogicByCharID(charID, EMODULE_ID_FRIEND, CENTER_TO_LOGIC_HANDSEL_ROSE, &c2lhandselRoseReq);

	return true;
}

bool RelationMgr::OnApplyRelationReq(CharIDType applyID, RECV_PACKAGE &package)
{
	ProtoBuf::CWApplyRelationReq addRelationReq;
	if (!addRelationReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("OnApplyRelationReq parse failed...");
		return false;
	}

	CharIDType applyedID = addRelationReq.playerid(); //被申请方的玩家ID
	ProtoBuf::ERetCode ret = OperateCheck(applyID, applyedID);
	if (RET_SUCCESS == ret)
	{
		HandlleApplyRelationReq(applyID, addRelationReq);
	}
	else if (RET_RELATION_HAVE_NO_DATA == ret)
	{
		QueryRelationDB(applyID, applyedID, RELATION_OPERATE_TYPE_APPLY, addRelationReq.SerializeAsString());
	}
	else
	{
		ProtoBuf::WCApplyRelationRsp addRelationRsp;
		addRelationRsp.set_ret(ret);
		addRelationRsp.set_playerid(applyedID);
		g_GetCenterService()->SendDataToClient(applyID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_APPLY_RELATION, &addRelationRsp);
	}
	return true;
}

bool RelationMgr::OnAgreeRelationReq(CharIDType agreeID, RECV_PACKAGE &package)
{
	ProtoBuf::CWAgreeRelationReq agreeRelationReq;
	if (!agreeRelationReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWAgreeRelationReq parse failed...");
		return false;
	}

	CharIDType applyID = agreeRelationReq.playerid(); //申请方的玩家ID
	ProtoBuf::ERetCode ret = OperateCheck(agreeID, applyID);
	if (RET_SUCCESS == ret)
	{
		HandleAgreeRelationReq(agreeID, agreeRelationReq);
	}
	else if (RET_RELATION_HAVE_NO_DATA == ret)
	{
		QueryRelationDB(agreeID, applyID, RELATION_OPERATE_TYPE_AGREE_OR_REFUSE, agreeRelationReq.SerializeAsString());
	}
	else
	{
		ProtoBuf::WCAgreeRelationRsp agreeRelationRsp;
		agreeRelationRsp.set_ret(RET_RELATION_APPLY_GROUP_ERROR);
		g_GetCenterService()->SendDataToClient(agreeID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_AGREE_RELATION, &agreeRelationRsp);
	}
	return false;
}

bool RelationMgr::OnOneKeyAgreeRelationReq(CharIDType agreeID, RECV_PACKAGE& package)
{
	ProtoBuf::CWOneKeyAgreeRelationReq oneKeyAgreeRelationReq;
	ProtoBuf::WCOneKeyAgreeRelationRsp oneKeyAgreeRelationRsp;

	if (!oneKeyAgreeRelationReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWOneKeyAgreeRelationReq parse failed...");
		return false;
	}

	ProtoBuf::ERetCode ret = OperateCheck(agreeID);
	if (RET_SUCCESS != ret)
	{
		return true;
	}

	Relation* pAgreeRelation = g_GetRelationMgr()->FindRelation(agreeID);
	if (nullptr == pAgreeRelation)
	{
		return false;
	}

	Relation::ApplyIDList applyIdList = pAgreeRelation->GetApplyIDList();
	VEC_UINT64 list;
	LoadList(applyIdList, list);

	if (list.size() > 0)
	{
		QueryRelationDBEx(agreeID, list, RELATION_OPERATE_TYPE_AGREE_ONEKEY, oneKeyAgreeRelationReq.SerializeAsString());
	}
	else
	{
		HandleOneKeyAgreeRelationReq(agreeID, oneKeyAgreeRelationReq);
	}

	return true;
}

bool RelationMgr::OnDeleteRelationReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWDeleteRelationReq deleteRelationReq;

	if (!deleteRelationReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWAgreeRelationReq parse failed...");
		return false;
	}

	ProtoBuf::ERetCode ret = OperateCheck(charID);
	if (RET_SUCCESS != ret)
	{
		return true;
	}

	VEC_UINT64 list;
	LoadList(deleteRelationReq, list);

	if (list.size() > 0)
	{
		QueryRelationDBEx(charID, list, RELATION_OPERATE_TYPE_DELETE, deleteRelationReq.SerializeAsString());
	}
	else
	{
		HandleDeleteRelationReq(charID, deleteRelationReq);
	}

	return true;
}

bool RelationMgr::OnRecentChatListReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWRecentChatListReq recentChatListReq;
	ProtoBuf::WCRecentChatListRsp recentChatListRsp;

	if (!recentChatListReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWRecentChatListReq parse failed...");
		return false;
	}

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("CWRecentChatListReq nullptr == pRelation failed...charID:%lu", charID);
		return false;
	}

	VEC_UINT64 deleteIds;
	Relation::RecentList recentList = pRelation->GetRecentList();
	for (Relation::RecentListIter iter = recentList.begin(); iter != recentList.end(); ++iter)
	{
		if (iter->id == 0)
		{
			continue;
		}

		OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(iter->id);
		//没有角色的话直接把将账号从自己的最近联系人中清除
		if (nullptr == pOfflineCharacterData)
		{
			deleteIds.push_back(iter->id);
			continue;
		}

		//黑名单角色保留不发
		if (pRelation->inBlack(iter->id))
		{
			continue;
		}

		ProtoBuf::CharacterPlayerMiniInfo* applyInfo = recentChatListRsp.add_recentlist();
		if (nullptr == applyInfo)
		{
			MMOLOG_FMT_ERROR("CWRecentChatListReq nullptr == applyInfo...charID:%lu", charID);
			continue;
		}
		applyInfo->set_playerid(iter->id);
		applyInfo->set_playername(pOfflineCharacterData->GetCharName());
		applyInfo->set_sex(pOfflineCharacterData->GetSex());
		applyInfo->set_level(pOfflineCharacterData->GetLevel());
		applyInfo->set_prof(pOfflineCharacterData->GetProf());
		applyInfo->set_recenttype(iter->recentType);
		applyInfo->set_recenttime(iter->recentTime);
		applyInfo->set_fightpower(pOfflineCharacterData->GetFight());
		applyInfo->set_camp(pOfflineCharacterData->GetCampID());
		//判断是否在线
		ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(iter->id);
		if (nullptr != pActiveCharacter)
		{
			applyInfo->set_online(true);
		}

		//判断是否组队
		if (g_GetTeamMgr()->GetTeamId(iter->id) > 0)
		{
			applyInfo->set_inteam(true);
		}
	}

	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_RECENT_CHAT_LIST, &recentChatListRsp);

	//做一下清除工作
	for (uint32_t i = 0; i < deleteIds.size(); i++)
	{
		pRelation->DeleteRecentList(deleteIds[i]);
	}

	return true;
}

bool RelationMgr::OnOneKeyFriendReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWOneKeyFriendReq oneKeyFriendReq;
	ProtoBuf::WCOneKeyFriendRsp oneKeyFriendRsp;

	if (!oneKeyFriendReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWOneKeyFriendReq parse failed...");
		return false;
	}

	bool again = oneKeyFriendReq.again();

	std::list<RecentPlayer> ids;
	ERetCode status = GetRandomOnlineUserEx(charID, again, ids);
	oneKeyFriendRsp.set_ret(status);

	if (status == RET_SUCCESS)
	{
		for (std::list<RecentPlayer>::iterator it = ids.begin(); it != ids.end(); ++it)
		{
			OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(it->id);
			//过滤账号不存在的角色
			if (nullptr == pOfflineCharacterData)
			{
				//MMOLOG_FMT_ERROR("[center] CWOneKeyFriendReq but OfflineCharacterData is nullptr,charID:%u ", it->id);
				continue;
			}

			ActiveCharacter* onlineActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(it->id);

			ProtoBuf::CharacterPlayerMiniInfo* recommendInfo = oneKeyFriendRsp.add_recommend();
			if (nullptr == recommendInfo)
			{
				LogErrFmtPrint("OnOneKeyFriendReq...cid:%lu,again:%d,status:%d,id:%lu", charID, (int32_t)again, status,it->id);
				continue;
			}
			recommendInfo->set_playerid(it->id);
			recommendInfo->set_playername(pOfflineCharacterData->GetCharName());
			recommendInfo->set_sex(pOfflineCharacterData->GetSex());
			recommendInfo->set_level(pOfflineCharacterData->GetLevel());
			recommendInfo->set_prof(pOfflineCharacterData->GetProf());
			recommendInfo->set_recenttype(it->recentType);
			recommendInfo->set_online(onlineActiveCharacter == nullptr ? false : true);
			recommendInfo->set_fightpower(pOfflineCharacterData->GetFight());
			recommendInfo->set_camp(pOfflineCharacterData->GetCampID());
		}
	}

	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ONEKEY_FRIEND, &oneKeyFriendRsp);
	return true;
}



bool RelationMgr::OnRelationInfoReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWRelationInfoReq relationInfoReq;
	ProtoBuf::WCRelationInfoRsp relationInfoRsp;

	if (!relationInfoReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWRelationInfoReq parse failed...");
		return false;
	}

	uint32_t groupIndex = relationInfoReq.groupindex();
	if (groupIndex < GROUP_FRIEND || groupIndex > GROUP_HATE)
	{
		MMOLOG_FMT_ERROR("[center] CWRelationInfoReq but groupIndex is error,CharID:%llu ", charID);
		return false;
	}

	ProtoBuf::ERetCode ret = OperateCheck(charID);
	if (RET_SUCCESS != ret)
	{
		return true;
	}

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("[center] CWRelationInfoReq nullptr == pRelation,CharID:%llu ", charID);
		return false;
	}

	Relation::GroupList groupList = pRelation->GetGroupList();
	RelationTeam::PlayerList& idList = groupList[groupIndex].playerList;

	VEC_UINT64 list;
	LoadList(idList, list);

	if (list.size() > 0)
	{
		QueryRelationDBEx(charID, list, RELATION_OPERATE_TYPE_INFO, relationInfoReq.SerializeAsString());
	}
	else
	{
		HandleRelationInfoReq(charID, relationInfoReq);
	}

	return true;
}

bool RelationMgr::OnSearchUserReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWSearchUserReq searchUserReq;
	ProtoBuf::WCSearchUserRsp searchUserRsp;

	if (!searchUserReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWSearchUserReq parse failed...");
		return false;
	}

	CharIDType searchID = searchUserReq.searchid();
	OfflineCharacterData* pOfflineCharacterData = nullptr;

	if (searchID > 0)
	{
		pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(searchID);
	}
	else
	{
		pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacterByName(searchUserReq.name().c_str());
	}

	if (nullptr != pOfflineCharacterData)
	{
		searchUserRsp.set_ret(RET_SUCCESS);
		ProtoBuf::CharacterPlayerMiniInfo* playerInfo = searchUserRsp.mutable_playerinfo();
		if (nullptr == playerInfo)
		{
			LogErrFmtPrint("RelationMgr::OnSearchUserReq...cid:%lu,searchID:%lu ", charID, searchID);
			return false;
		}
		playerInfo->set_playerid(pOfflineCharacterData->GetCharID());
		playerInfo->set_playername(pOfflineCharacterData->GetCharName());
		playerInfo->set_sex(pOfflineCharacterData->GetSex());
		playerInfo->set_level(pOfflineCharacterData->GetLevel());
		playerInfo->set_prof(pOfflineCharacterData->GetProf());
		playerInfo->set_fightpower(pOfflineCharacterData->GetFight());
		playerInfo->set_camp(pOfflineCharacterData->GetCampID());

		//判断是否在线
		ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(pOfflineCharacterData->GetCharID());
		if (nullptr != pActiveCharacter)
			playerInfo->set_online(true);
		else
			playerInfo->set_online(false);
	}
	else
	{
		searchUserRsp.set_ret(RET_RELATION_NOT_SEARCH);
	}

	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_SEARCH_USER, &searchUserRsp);
	return true;
}

bool RelationMgr::OnGivePhysicalReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWGivePhyscialReq givePhyscialReq;
	ProtoBuf::WCGivePhyscialRsp givePhyscialRsp;

	if (!givePhyscialReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWGivePhyscialReq parse failed...");
		return false;
	}

	CharIDType dstID = givePhyscialReq.playerid();
	ProtoBuf::ERetCode ret = OperateCheck(charID, dstID);
	if (RET_SUCCESS == ret)
	{
		HandleGivePhysicalReq(charID, givePhyscialReq);
	}
	else if (RET_RELATION_HAVE_NO_DATA == ret)
	{
		QueryRelationDB(charID, dstID, RELATION_OPERATE_TYPE_GIVE, givePhyscialReq.SerializeAsString());
	}
	else
	{
		givePhyscialRsp.set_ret(ret);
		givePhyscialRsp.set_playerid(dstID);
		g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_GIVE_PHYSICAL, &givePhyscialRsp);
	}

	return true;
}

bool RelationMgr::OnAllGivePhysicalReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWAllGivePhyscialReq allGivePhyscialReq;
	if (!allGivePhyscialReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWAllGivePhyscialReq parse failed...");
		return false;
	}

	ProtoBuf::ERetCode ret = OperateCheck(charID);
	if (RET_SUCCESS != ret)
	{
		return false;
	}

	VEC_UINT64 list;
	LoadList(allGivePhyscialReq, list);

	if (list.size() > 0)
	{
		QueryRelationDBEx(charID, list, RELATION_OPERATE_TYPE_GIVE_ONEKEY, allGivePhyscialReq.SerializeAsString());
	}
	else
	{
		HandleAllGivePhysicalReq(charID, allGivePhyscialReq);
	}

	return true;
}

bool RelationMgr::OnGetPhysicalReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWGetPhyscialReq getPhyscialReq;
	if (!getPhyscialReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWGetPhyscialReq parse failed...");
		return false;
	}

	CharIDType srcID = charID;
	CharIDType dstID = getPhyscialReq.playerid();

	ProtoBuf::ERetCode ret = OperateCheck(srcID, dstID);
	if (RET_SUCCESS == ret)
	{
		HandleGetPhysicalReq(srcID, getPhyscialReq);
	}
	else if (RET_RELATION_HAVE_NO_DATA == ret)
	{
		QueryRelationDB(srcID, dstID, RELATION_OPERATE_TYPE_GET, getPhyscialReq.SerializeAsString());
	}
	else
	{
		ProtoBuf::WCGetPhyscialRsp getPhyscialRsp;
		getPhyscialRsp.set_ret(ret);
		getPhyscialRsp.set_playerid(dstID);
		g_GetCenterService()->SendDataToClient(srcID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_GET_PHYSICAL, &getPhyscialRsp);
	}

	return true;
}

bool RelationMgr::OnGetPhysicalGiftReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWGetPhysicalGiftReq getPhyscialGiftReq;
	ProtoBuf::WCGetPhysicalGiftRsp getPhyscialGiftRsp;

	if (!getPhyscialGiftReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWGetPhysicalGiftReq parse failed...");
		return false;
	}

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("[center] CWGetPhysicalGiftReq but pRelation is nullptr,charID:%u ", charID);
		return false;
	}

	if (pRelation->CanGetPhyGift())
	{
		getPhyscialGiftRsp.set_ret(RET_SUCCESS);

		//发往逻辑服添加礼包
		WLGetPhysicalGiftReq notify;
		notify.set_playerid(charID);
		g_GetCenterService()->SendDataToLogicByCharID(charID, EMODULE_ID_FRIEND, CENTER_SERVER_PROTOCOL_GET_PHYSICAL_GIFT_TO_LOGIC, &notify);
		return true;
	}

	getPhyscialGiftRsp.set_ret(RET_RELATION_GET_PHYSICAL_GIFT_LIMIT);
	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_GET_PHYSICAL_GIFT, &getPhyscialGiftRsp);
	return true;
}

bool RelationMgr::OnApplyListReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWApplyListReq applyListReq;
	ProtoBuf::WCApplyListRsp applyListRsp;

	if (!applyListReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWApplyListReq parse failed...");
		return false;
	}

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("[center] CWApplyListReq but pRelation is nullptr,CharID:%u ", charID);
		return false;
	}

	VEC_UINT64 deleteIds;
	Relation::ApplyIDList applyIDList = pRelation->GetApplyIDList();
	Relation::ApplyIDListpIter iter = applyIDList.begin();
	for (; iter != applyIDList.end(); ++iter)
	{
		OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(*iter);
		if (nullptr == pOfflineCharacterData)
		{
			deleteIds.push_back(*iter);
			continue;
		}

		ProtoBuf::CharacterPlayerMiniInfo* miniInfo = applyListRsp.add_applyinfo();
		if (nullptr == miniInfo)
		{
			LogErrFmtPrint("OnApplyListReq...cid:%lu,delid:%lu ", charID, (*iter));
			continue;
		}

		miniInfo->set_playerid(*iter);
		miniInfo->set_playername(pOfflineCharacterData->GetCharName());
		miniInfo->set_sex(pOfflineCharacterData->GetSex());
		miniInfo->set_level(pOfflineCharacterData->GetLevel());
		miniInfo->set_prof(pOfflineCharacterData->GetProf());
		miniInfo->set_fightpower(pOfflineCharacterData->GetFight());
		miniInfo->set_camp(pOfflineCharacterData->GetCampID());
	}

	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_APPLYLIST, &applyListRsp);

	//最后做一下清除工作
	for (uint32_t i = 0; i < deleteIds.size(); i++)
	{
		pRelation->DeleteApply(deleteIds[i]);
	}
	return true;
}

bool RelationMgr::OnClearApplyListReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWClearApplyListReq clearApplyListReq;
	ProtoBuf::WCClearApplyListRsp clearApplyListRsp;

	if (!clearApplyListReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWClearApplyListReq parse failed...");
		return false;
	}

	Relation* pRelation = FindRelation(charID);
	if (nullptr == pRelation)
	{
		MMOLOG_FMT_ERROR("[center] CWClearApplyListReq but pRelation is nullptr,CharID:%llu ", charID);
		return false;
	}

	pRelation->ClearApply();

	clearApplyListRsp.set_ret(RET_SUCCESS);
	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_CLEARAPPLYLIST, &clearApplyListRsp);
	return true;
}

bool RelationMgr::OnAddRecentListReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::CWAddRecentListReq addRecentListReq;
	ProtoBuf::WCAddRecentListRsp addRecentListRsp;

	if (!addRecentListReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("CWAddRecentListReq parse failed...");
		return false;
	}

	CharIDType dstId = addRecentListReq.dstid();
	string strDstName = addRecentListReq.dstname();
	if (0 == dstId)
	{
		OfflineCharacterData *pDstOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacterByName(strDstName.c_str());
		if (nullptr == pDstOfflineCharacterData)
		{
			addRecentListRsp.set_ret(RET_NOT_HAVE_CHARACTER);
			g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ADDRECENTLIST, &addRecentListRsp);
			return true;
		}
		dstId = pDstOfflineCharacterData->GetCharID();
	}

	ERetCode ret = UpdateRecentList(charID, dstId, RELATION_RECENT_CHAT);
	if (ret == RET_RELATION_HAVE_NO_DATA)
	{
		return true;
	}
	else if (ret == RET_SUCCESS)
	{
		ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(dstId);
		addRecentListRsp.set_online(pActiveCharacter == nullptr ? false : true);
		addRecentListRsp.set_dstid(dstId);
	}

	addRecentListRsp.set_ret(ret);
	g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ADDRECENTLIST, &addRecentListRsp);

	return true;
}

bool RelationMgr::OnHandselRoseReq(CharIDType charID, RECV_PACKAGE &package)
{
	ProtoBuf::HandselRoseReq handselRoseReq;
	ProtoBuf::HandselRoseRsp handselRoseRsp;

	if (!handselRoseReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("handselRoseReq parse failed...");
		return false;
	}

	CharIDType dstID = handselRoseReq.dst_char_id();
	ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(dstID);
	if (nullptr == pActiveCharacter)
	{
		handselRoseRsp.set_ret(RET_PLAYER_NOT_ONLINE);
		g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_HANDSEL_ROSE, &handselRoseRsp);
		return false;
	}

	ProtoBuf::ERetCode ret = OperateCheck(charID, dstID);
	if (RET_SUCCESS == ret)
	{
		HandleHandselRoseReq(charID, handselRoseReq);
	}
	else if (RET_RELATION_HAVE_NO_DATA == ret)
	{
		QueryRelationDB(charID, dstID, RELATION_OPERATE_TYPE_ROSE, handselRoseReq.SerializeAsString());
	}
	else
	{
		handselRoseRsp.set_ret(ret);
		g_GetCenterService()->SendDataToClient(charID, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_HANDSEL_ROSE, &handselRoseRsp);
	}

	return true;
}

bool RelationMgr::OnAddHateListReq(RECV_PACKAGE &package)
{
	ProtoBuf::GWAddHateReq addHateReq;
	ProtoBuf::WCApplyRelationRsp addRelationRsp;

	if (!addHateReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("addHateReq parse failed...");
		return false;
	}

	CharIDType srcID = addHateReq.srcid();
	CharIDType dstID = addHateReq.dstid();
	ProtoBuf::ERetCode ret = AddRelation(GROUP_HATE, srcID, dstID);

	if (ret == RET_SUCCESS)
	{
		//如果仇恨一方摘要数据没有了则为出错
		OfflineCharacterData *pOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(dstID);
		if (nullptr == pOfflineCharacterData)
		{
			MMOLOG_FMT_ERROR("[center] OnAddHateListReq add hate but OfflineCharacterData is nullptr,applyedID:%llu ", dstID);
			return false;
		}

		//将仇恨方的信息发送给添加方
		ProtoBuf::WCNotifyRelationRsp notify;
		notify.set_ret(RET_SUCCESS);
		notify.set_groupindex(GROUP_HATE);
		ProtoBuf::CharacterPlayerMiniInfo* applyedInfo = notify.mutable_friendinfo();
		applyedInfo->set_playerid(dstID);
		applyedInfo->set_playername(pOfflineCharacterData->GetCharName());
		applyedInfo->set_sex(pOfflineCharacterData->GetSex());
		applyedInfo->set_level(pOfflineCharacterData->GetLevel());
		applyedInfo->set_prof(pOfflineCharacterData->GetProf());
		applyedInfo->set_fightpower(pOfflineCharacterData->GetFight());
		applyedInfo->set_camp(pOfflineCharacterData->GetCampID());
		g_GetCenterService()->SendDataToClient(srcID, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_NOTIFY_RELATION, &notify);
	}
	return true;
}

bool RelationMgr::OnTrackHateReq(RECV_PACKAGE &package)
{
	ProtoBuf::TrackHateReq trackHateReq;
	ProtoBuf::WGTrackHateError trackHateError;

	if (!trackHateReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("trackHateReq parse failed...");
		return false;
	}

	CharIDType hateID = trackHateReq.hateid();
	CharIDType charID = trackHateReq.charid();

	//错误情况一 仇恨角色已经不存在了 被删除了
	OfflineCharacterData *pHateCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(hateID);
	if (nullptr == pHateCharacterData)
	{
		trackHateError.set_ret(RET_NOT_HAVE_CHARACTER);
		trackHateError.set_charid(charID);
		g_GetCenterService()->SendDataToLogicByCharID(charID, EMODULE_ID_FRIEND, CENTER_TO_LOGIC_TRACK_ERROR, &trackHateError);
		return false;
	}

	//错误情况二 仇恨角色已经下线了
	ActiveCharacter* pHateActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(hateID);
	if (nullptr == pHateActiveCharacter)
	{
		trackHateError.set_ret(RET_NOT_ONLINE);
		trackHateError.set_charid(charID);
		g_GetCenterService()->SendDataToLogicByCharID(charID, EMODULE_ID_FRIEND, CENTER_TO_LOGIC_TRACK_ERROR, &trackHateError);
		return false;
	}

	//通知仇恨一方拉取位置信息
	trackHateReq.set_charid(charID);
	trackHateReq.set_hateid(hateID);
	g_GetCenterService()->SendDataToLogicByCharID(hateID, EMODULE_ID_FRIEND, CENTER_TO_LOGIC_TRACK_HATE, &trackHateReq);
	return true;
}

bool RelationMgr::OnTrackHateScuess(RECV_PACKAGE &package)
{
	ProtoBuf::GWTrackHateScuess trackHateSucess;
	ProtoBuf::WCTrackHateRsp rsp;
	if (!trackHateSucess.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("GWTrackHateScuess parse failed...");
		return false;
	}

	CharIDType charId = trackHateSucess.charid();
	//rsp.set_ret(RET_SUCCESS);
	rsp.set_ret(trackHateSucess.ret());
	rsp.set_hatdid(trackHateSucess.hateid());
	rsp.set_sceneid(trackHateSucess.sceneid());
	rsp.mutable_dstpos()->CopyFrom(trackHateSucess.dstpos());
	g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_TRACK_HATE, &rsp);

	//里要返回给逻辑服扣除道具
	if (RET_SUCCESS == trackHateSucess.ret())
	{
		GWRelationCostSth cost;
		cost.set_charid(charId);
		cost.set_itemid(RELATION_TRACK_HATE_GOODID);
		cost.set_count(1);
		g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_COST_STH, &cost);
	}
	
	return true;
}

bool RelationMgr::OnHandselRoseRsp(RECV_PACKAGE &package)
{
	ProtoBuf::L2CHandselRoseRsp l2cHandselRoseRsp;
	if (!l2cHandselRoseRsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("OnHandselRsp parse failed...");
		return false;
	}

	CharIDType charId = l2cHandselRoseRsp.charid();
	CharIDType dstId = l2cHandselRoseRsp.dst_char_id();
	uint32_t addCharm = l2cHandselRoseRsp.charm();
	uint32_t itemCount = l2cHandselRoseRsp.item_count();

	if (RET_SUCCESS == l2cHandselRoseRsp.ret())
	{
		//加魅力值
		AddCharm(dstId, addCharm);

		//加亲密度
		Relation* pSrcRelation = FindRelation(charId);
		if (nullptr != pSrcRelation && pSrcRelation->IsMyfriend(dstId))
			pSrcRelation->AddCloseness(dstId, RELATION_CLOSENESS_HANDSEL_ROSE, addCharm);

		Relation* pDstRelation = FindRelation(dstId);
		if (nullptr != pDstRelation && pDstRelation->IsMyfriend(charId))
			pDstRelation->AddCloseness(charId, RELATION_CLOSENESS_HANDSEL_ROSE, addCharm);

		SystemChatMsgData msgData;
		msgData.Clear();

		CharacterPlayerMiniInfo charInfo;
		g_GetChatCenter()->InitPlayerMiniInfoStruct(charId, charInfo);
		CharacterPlayerMiniInfo dstInfo;
		g_GetChatCenter()->InitPlayerMiniInfoStruct(dstId, dstInfo);

		SET_UINT64 iSet;
		iSet.insert(dstId);
		msgData.players.push_back(charInfo);
		msgData.params.push_back(itemCount);
		msgData.text.push_back(l2cHandselRoseRsp.item_name());
		msgData.params.push_back(addCharm);
		g_GetChatCenter()->SendBroadcastChat(BT_FRIEND_ROSE_HANDSEL_GOOD, msgData, iSet);

		msgData.Clear();
		msgData.players.push_back(charInfo);
		msgData.players.push_back(dstInfo);
		msgData.params.push_back(itemCount);
		msgData.text.push_back(l2cHandselRoseRsp.item_name());
		g_GetChatCenter()->SendWorldBroadcastChat(BT_FRIEND_ROSE_HANDSEL_WONDER, msgData);

		g_GetTeamMgr()->TeamClosenessUpdate(charId);
	}
	
	HandselRoseRsp rsp;
	rsp.set_ret(l2cHandselRoseRsp.ret());
	g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_FRIEND, SERVER_TO_CLIENT_HANDSEL_ROSE, &rsp);
	
	return true;
}

void RelationMgr::onDBProxyMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case DBPROXY_PROTOCOL_ALL_FRIEND_DATA_RSP:
		{
			AllFriendDBResponse rsp;
			if (!rsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
			{
				MMOLOG_FMT_ERROR("[center] RelationDataDBResponse return but parse failed....offset:%d,", rsp.offset());
				return;
			}
			LoadRelationDataDBRet(rsp);
		}
		break;
	case DBPROXY_PROTOCOL_FRIEND_DATA_RSP:
		{
			FriendDBResponse rsp;
			if (!rsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
			{
				MMOLOG_FMT_ERROR("[center] FriendDBResponse return but parse failed....");
				return;
			}
			LoadCharRelationDataDBRet(rsp);
		}
		break;
	default:
		break;
	}
}

void RelationMgr::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case LOGIC_TO_CENTER_ADD_HATE:
	{
		OnAddHateListReq(package);
		break;
	}
	case LOGIC_TO_CENTER_TRACK_HATE:
	{
		OnTrackHateReq(package);
		break;
	}
	case LOGIC_TO_CENTER_TRACK_SUCESS:
	{
		OnTrackHateScuess(package);
		break;
	}
	case LOGIC_TO_CENTER_HANDSEL_ROSE:
	{
		OnHandselRoseRsp(package);
		break;
	}
	default:
		break;
	}
}

void RelationMgr::LoadRelationDataDBRet(AllFriendDBResponse &rsp)
{
	int32_t offset = rsp.offset();
	int32_t size = rsp.info_size();
	bool bFlag = true;
	for (int32_t i = 0; i < size; ++i)
	{
		FriendDBInfo *pInfo = rsp.mutable_info(i);
		if (nullptr != pInfo)
		{
			CharIDType charID = pInfo->charid();
			const RelationDBInfo &relationInfo = pInfo->data();

			if (FindRelation(charID))
			{
				bFlag = false;
				MMOLOG_FMT_ERROR("[center] LoadRelationDataDBRet already loaded...charID:%llu ", charID);
				return;
			}

			Relation *pRelation = MakeRelation();
			if (nullptr == pRelation)
			{
				bFlag = false;
				MMOLOG_FMT_ERROR("[center] LoadRelationDataDBRet nullptr == pRelation...charid:%llu", charID);
				return;
			}

			pRelation->LoadData(relationInfo);

			_relationMap[charID] = pRelation;
		}
		else
		{
			bFlag = false;
			MMOLOG_FMT_ERROR("[center] LoadRelationDataDBRet nullptr == pInfo");
			return;
		}
	}
	if (bFlag)
	{
		/*if (size >= MAX_RELATION_DATA_COUNT_PER_LOAD)
		{
			offset += size;
			AllFriendDBRequest req;
			req.set_offset(offset);
			req.set_retnum(MAX_RELATION_DATA_COUNT_PER_LOAD);
			if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_ALL_FRIEND_DATA_REQ, &req))
			{
				MMOLOG_FMT_ERROR("[center] LoadRelationDataDBRet SendDataToDBProxy failed...offset:%d ", offset);
			}
		}
		else
		{
			//已经加载完成
			uint64_t nNowTime = Time::Now().sec();
			uint64_t nInterTime = nNowTime - m_nStartLoadTime;
			//设置加载完成
			m_bFinishLoad = true;
			int32_t nTotal = (int32_t)_relationMap.size();
			MMOLOG_FMT_INFO("[center] LoadRelationDataDBRet finished.... total_count:%d , total_sec:%lld  ", nTotal, nInterTime);
		}*/

		if (size > 0)
		{
			LogInfoFmtPrint("LoadRelationDataDBRet...offset:%d , size:%d ", offset, size);
			offset += size;
			AllFriendDBRequest req;
			req.set_offset(offset);
			if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_ALL_FRIEND_DATA_REQ, &req))
			{
				MMOLOG_FMT_ERROR("[center] LoadRelationDataDBRet SendDataToDBProxy failed...offset:%d ", offset);
			}
		}
		else
		{
			//已经加载完成
			uint64_t nNowTime = Time::Now().sec();
			uint64_t nInterTime = nNowTime - m_nStartLoadTime;
			//设置加载完成
			m_bFinishLoad = true;
			int32_t nTotal = (int32_t)_relationMap.size();
			MMOLOG_FMT_INFO("[center] LoadRelationDataDBRet finished.... total_count:%d , total_sec:%lld  ", nTotal, nInterTime);
		}

	}
}

void RelationMgr::LoadCharRelationDataDBRet(FriendDBResponse &rsp)
{
	if (RET_SUCCESS != rsp.retcode())
	{
		MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet RET_SUCCESS != rsp.retcode()...retcode:%d,operateType:%d", rsp.retcode(), rsp.operate_type());
		return;
	}

	CharIDType operateCharId = rsp.charid();
	uint32_t operateType = rsp.operate_type();
	if (operateType >= RELATION_OPERATE_TYPE_LIMIT || operateType <= RELATION_OPERATE_TYPE_NONE)
	{
		MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet operateType is error...operateType:%d", operateType);
		return;
	}

	for (int32_t i = 0; i != rsp.info_lst_size(); ++i)
	{
		const FriendDBInfo &friendInfo = rsp.info_lst(i);
		CharIDType charId = friendInfo.charid();
		Relation *pRelation = FindRelation(charId);
		if (nullptr != pRelation)
		{
			continue;
		}
		pRelation = MutRelation(charId);
		if (nullptr == pRelation)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet nullptr == pRelation...charid:%llu, operateType:%d", charId, operateType);
			continue;
		}
		pRelation->LoadData(friendInfo.data());
		_relationMap[charId] = pRelation;
	}

	switch (operateType)
	{
	case RELATION_OPERATE_TYPE_LOAD:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...  rsp.last_lst_size() > 0 error...operateType:%d", operateType);
			return;
		}
		Relation *pRelation = FindRelation(operateCharId);
		if (nullptr == pRelation)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet... nullptr == pRelation...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		RelationLogin(pRelation, operateCharId);
	}
	break;

	case RELATION_OPERATE_TYPE_APPLY:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...rsp.last_lst_size() > 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		ProtoBuf::CWApplyRelationReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWApplyRelationReq parase failed...");
			return;
		}

		HandlleApplyRelationReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_AGREE_OR_REFUSE:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...rsp.last_lst_size() > 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		ProtoBuf::CWAgreeRelationReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWAgreeRelationReq parase failed...");
			return;
		}

		HandleAgreeRelationReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_AGREE_ONEKEY:
	{
		if (rsp.last_lst_size() > 0)	//等好友数据全部加载完成 再处理业务
		{
			break;
		}

		ProtoBuf::CWOneKeyAgreeRelationReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWOneKeyAgreeRelationReq parase failed...");
			return;
		}

		HandleOneKeyAgreeRelationReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_DELETE:
	{
		if (rsp.last_lst_size() > 0)	//等好友数据全部加载完成 再处理业务
		{
			break;
		}

		ProtoBuf::CWDeleteRelationReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWDeleteRelationReq parase failed...");
			return;
		}

		HandleDeleteRelationReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_INFO:
	{
		if (rsp.last_lst_size() > 0)	//等好友数据全部加载完成 再处理业务
		{
			break;
		}
		ProtoBuf::CWRelationInfoReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWRelationInfoReq parase failed...");
			return;
		}

		HandleRelationInfoReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_GIVE:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet... rsp.last_lst_size() > 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		ProtoBuf::CWGivePhyscialReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWGivePhyscialReq parase failed...");
			return;
		}

		HandleGivePhysicalReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_GIVE_ONEKEY:
	{
		if (rsp.last_lst_size() > 0)	//等好友数据全部加载完成 再处理业务
		{
			break;
		}

		ProtoBuf::CWAllGivePhyscialReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWAllGivePhyscialReq parase failed...");
			return;
		}

		HandleAllGivePhysicalReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_ROSE:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...rsp.last_lst_size() > 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		ProtoBuf::HandselRoseReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] HandselRoseReq parase failed...");
			return;
		}

		HandleHandselRoseReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_GET:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...rsp.last_lst_size() > 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		ProtoBuf::CWGetPhyscialReq req;
		if (!req.ParseFromArray(rsp.data().c_str(), (int32_t)rsp.data().length()))
		{
			MMOLOG_FMT_ERROR("[center] CWGetPhyscialReq parase failed...");
			return;
		}

		HandleGetPhysicalReq(operateCharId, req);
	}
	break;

	case RELATION_OPERATE_TYPE_RECENT:
	{
		if (rsp.last_lst_size() > 0)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...rsp.last_lst_size() > 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		if (rsp.info_lst_size() != 1)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...rsp.info_lst_size() != 0...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		Relation* pSrcRelation = FindRelation(operateCharId);
		if (nullptr == pSrcRelation)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...nullptr == pSrcRelation...operateType:%d, charid:%llu", operateType, operateCharId);
			return;
		}

		CharIDType dstId = rsp.info_lst(0).charid();
		Relation* pDstRelation = FindRelation(dstId);
		if (nullptr == pDstRelation)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...nullptr == pDstRelation...operateType:%d, dstId:%llu", operateType, dstId);
			return;
		}

		uint32_t type = atoi(rsp.data().c_str());
		if (type > RELATION_RECENT_SYSTEM || type < RELATION_RECENT_CHAT)
		{
			MMOLOG_FMT_ERROR("[center] LoadCharRelationDataDBRet...recent type is error...operateType:%d, type:%d", operateType, type);
			return;
		}

		pSrcRelation->UpdateRecentList(dstId, type);
		pDstRelation->UpdateRecentList(operateCharId, type);

		if (type == RELATION_RECENT_CHAT)
		{
			ProtoBuf::WCAddRecentListRsp addRecentListRsp;
			ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(dstId);
			addRecentListRsp.set_online(pActiveCharacter == nullptr ? false : true);
			addRecentListRsp.set_dstid(dstId);
			addRecentListRsp.set_ret(RET_SUCCESS);
			g_GetCenterService()->SendDataToClient(operateCharId, EMODULE_ID_FRIEND, CENTER_TO_CLIENT_ADDRECENTLIST, &addRecentListRsp);
		}
	}
	break;

	default:
		break;
	}
	
	if (rsp.query_times() >= 50)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::LoadCharRelationDataDBRet query times so many times...operateCharId:%llu operateType:%d", operateCharId, rsp.query_times());
		return;
	}

	if (rsp.last_lst().size() > 0)
	{
		if (g_GetCenterService()->IsConnectDBProxy())
		{
			FriendDBRequest req;
			req.set_charid(operateCharId);
			req.mutable_dstid_lst()->CopyFrom(rsp.last_lst());
			req.set_operate_type(operateType);
			req.set_data(rsp.data());
			req.set_query_times(rsp.query_times() + 1);
			if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_FRIEND_DATA_REQ, &req))
			{
				MMOLOG_FMT_ERROR("[center] RelationMgr::LoadCharRelationDataDBRet SendDataToDBProxy failed...operateCharId:%llu ", operateCharId);
			}
			else
			{
				LogDebugFmtPrint("[center] RelationMgr::LoadCharRelationDataDBRet start login load character relation data....");
			}
		}
	}
}

bool RelationMgr::Update(uint64_t tick, bool isDump)
{
	_UNUSE(tick);
	uint64_t currTime = ServerTime::UnixSec();
	if (currTime >= (m_lastSaveTime + INTRAVAL_SAVE_RELATIONDATA) || isDump)
	{
		//std::map<CharIDType, bool> isSaveMap;
		RelationIter iter = _relationMap.begin();
		for (; iter != _relationMap.end(); ++iter)
		{
			if (nullptr != iter->second)
			{
				if (iter->second->IsChange())
				{
					SaveFriendDBRequest saveData;
					FriendDBInfo* pFriendDBInfo = saveData.add_info();
					if (nullptr != pFriendDBInfo)
					{
						pFriendDBInfo->set_charid(iter->first);
						RelationDBInfo* pInfo = pFriendDBInfo->mutable_data();
						if (nullptr != pInfo)
						{
							iter->second->SaveDate(*pInfo);
							if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_FRIEND, DBPROXY_PROTOCOL_SAVE_FRIEND_DATA_REQ, &saveData))
							{
								MMOLOG_FMT_ERROR("[center] RelationMgr::Update SendSaveRelationDataToDBProxy failed....cid:%lu ", iter->first);
							}
						}
						else
						{
							LogErrFmtPrint("[center] RelationMgr::Update....nullptr == pInfo cid:%lu ", iter->first);
						}
					}
					else
					{
						LogErrFmtPrint("[center] RelationMgr::Update....nullptr == pFriendDBInfo cid:%lu ", iter->first);
					}
				} // end of if (iter->second->IsChange())
			} // end of if (nullptr != iter->second)
		} // end of for (; iter != _relationMap.end(); ++iter)

		m_lastSaveTime = currTime;
	}

	return true;
}

Relation* RelationMgr::MutRelation(CharIDType playerID)
{
	RelationIter iter = _relationMap.find(playerID);
	if (iter == _relationMap.end())
	{
		Relation* relation = _relationPool->MallocObj();
		if (nullptr == relation)
		{
			LogErrFmtPrint("[center] RelationMgr::MutRelation....nullptr == relation cid:%lu ", playerID);
			return nullptr;
		}
		
		_relationMap[playerID] = relation;
		return relation;
	}
	
	return iter->second;
}

Relation* RelationMgr::FindRelation(CharIDType playerID)
{
	RelationIter iter = _relationMap.find(playerID);
	if (iter == _relationMap.end())
	{
		return nullptr;
	}

	iter->second->AddActive();
	return iter->second;
}

Relation* RelationMgr::MakeRelation()
{
	if (nullptr == _relationPool)
	{
		return nullptr;
	}
	return _relationPool->MallocObj();
}

ProtoBuf::ERetCode RelationMgr::ApplyAddFrined(CharIDType applyID, CharIDType applyedID)
{
	OfflineCharacterData *pApplyOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
	if (nullptr == pApplyOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	OfflineCharacterData *pApplyedOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyedID);
	if (nullptr == pApplyedOfflineCharacterData)
	{
		return RET_NOT_HAVE_CHARACTER;
	}

	Relation* pApplyRelation = FindRelation(applyID);
	if (nullptr == pApplyRelation)
	{
		return RET_FAIL;
	}

	Relation* pApplyedRelation = FindRelation(applyedID);
	if (nullptr == pApplyedRelation)
	{
		return RET_FAIL;
	}

	//自己不能申请添加自己为好友
	if (applyID == applyedID)
	{
		return RET_RELATION_CAN_NOT_APPLY_SELF;
	}

	//判断申请方人数是否好友人数是否已达到上限
	//if (pApplyRelation->FriendNumLimit())
	//{
	//	return RET_RELATION_SIZE_LIMIT_NO_APPLY;
	//}

	////判断被被申请人好友人数上限
	//if (pApplyedRelation->FriendNumLimit())
	//{
	//	return RET_RELATION_SIZE_LIMIT_NO_APPLY_OTHER;
	//}

	//判断申请方是否在被申请方黑名单中了
	if (pApplyedRelation->inBlack(applyID))
	{
		return RET_RELATION_IN_OTHER_BALCK_CAN_NOT_APPLY;
	}

	//判断被申请方是否在申请方的黑名单中
	if (pApplyRelation->inBlack(applyedID))
	{
		return RET_RELATION_IN_YOUR_BALCK_CAN_NOT_APPLY;
	}

	//判断双方是已经是好友关系了
	if (pApplyRelation->IsMyfriend(applyedID))
	{
		return RET_RELATION_IS_MY_FRIEND;
	}

	//如果双方不是双向好友需要做一下容错
	if (pApplyedRelation->IsMyfriend(applyID))
	{
		pApplyedRelation->DelUser(GROUP_FRIEND, applyID);

	}

	//如果之前已经申请过了
	bool bSuccess = pApplyedRelation->AddApply(applyID);
	if (!bSuccess)
	{
		return RET_RELATION_HAVE_APPLY;
	}

	return RET_SUCCESS;
}

ProtoBuf::ERetCode RelationMgr::AddBlack(CharIDType applyID, CharIDType applyedID)
{
	OfflineCharacterData *pApplyOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
	if (nullptr == pApplyOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	OfflineCharacterData *pApplyedOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyedID);
	if (nullptr == pApplyedOfflineCharacterData)
	{
		return RET_NOT_HAVE_CHARACTER;
	}

	Relation* pApplyRelation = FindRelation(applyID);
	if (nullptr == pApplyRelation)
	{
		return RET_FAIL;
	}

	Relation* pApplyedRelation = FindRelation(applyedID);
	if (nullptr == pApplyedRelation)
	{
		return RET_FAIL;
	}

	//自己不能申请添加自己为好友
	if (applyID == applyedID)
	{
		return RET_RELATION_ADD_BLACK_MYSELF;
	}

	//黑名单数量是否已经达到上限了
	if (pApplyRelation->BlackNumLimit())
	{
		return RET_RELATION_BALCK_SIZE_LIMIT;
	}

	//对方是否在你的黑名单中
	if (pApplyRelation->inBlack(applyedID))
	{
		return RET_RELATION_IN_YOUR_BALCK;
	}

	//先解除双方的好友关系
	pApplyRelation->DelUser(GROUP_FRIEND, applyedID);
	pApplyedRelation->DelUser(GROUP_FRIEND, applyID);

	//添加近黑名单
	pApplyRelation->AddUser(GROUP_BLACK, applyedID);

	return RET_SUCCESS;
}

ProtoBuf::ERetCode RelationMgr::AgreeAddFriend(CharIDType agreeID, CharIDType applyID)
{
	OfflineCharacterData *pAgreeOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(agreeID);
	if (nullptr == pAgreeOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	Relation* pAgreeRelation = FindRelation(agreeID);
	if (nullptr == pAgreeRelation)
	{
		return RET_FAIL;
	}

	OfflineCharacterData *pApplyOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
	if (nullptr == pApplyOfflineCharacterData)
	{
		//这种情况直接清空申请列表
		pAgreeRelation->DeleteApply(applyID);
		return RET_NOT_HAVE_CHARACTER;
	}

	//不能添加自己
	if (applyID == agreeID)
	{
		return RET_RELATION_NOT_ADD_SELF;
	}

	//判断同意方人数是否好友人数是否已达到上限
	if (pAgreeRelation->FriendNumLimit())
	{
		return RET_RELATION_SIZE_LIMIT_NO_ADD;
	}

	//判断申请方是否在同意方黑名单中了
	if (pAgreeRelation->inBlack(applyID))
	{
		return RET_RELATION_IN_OTHER_BALCK_CAN_NOT_APPLY;
	}

	//判断双方是已经是好友关系了
	if (pAgreeRelation->IsMyfriend(applyID))
	{
		return RET_RELATION_IS_MY_FRIEND;
	}

	//是否在申请列表中
	if (!pAgreeRelation->HaveApply(applyID))
	{
		return RET_RELATION_NOT_IN_APPLY;
	}

	Relation* pApplyRelation = FindRelation(applyID);
	if (nullptr == pApplyRelation)
	{
		return RET_FAIL;
	}

	//判断申请人好友人数上限
	if (pApplyRelation->FriendNumLimit())
	{
		return RET_RELATION_SIZE_LIMIT_NO_ADD_OTHER;
	}

	//判断同意方是否在申请方的黑名单中
	if (pApplyRelation->inBlack(agreeID))
	{
		return RET_RELATION_IN_YOUR_BALCK_CAN_NOT_APPLY;
	}

	//如果双方不是双向好友需要做一下容错
	if (pApplyRelation->IsMyfriend(agreeID))
	{
		pApplyRelation->DelUser(GROUP_FRIEND, agreeID);
	}

	//添加好友
	pAgreeRelation->AddUser(GROUP_FRIEND, applyID);
	pApplyRelation->AddUser(GROUP_FRIEND, agreeID);

	//清除申请列表
	pAgreeRelation->DeleteApply(applyID);

	//好友双方如果在同一队伍 处理加亲密度
	g_GetTeamMgr()->AddRelationInTeam(agreeID, applyID);

	ActiveCharacter* pApplyActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(applyID);
	if (nullptr == pApplyActiveCharacter)
	{
		pApplyRelation->AddFriendsAdd();
	}
	else
	{
		NotifyLogicAddFriend(applyID, 1);
	}
	NotifyLogicAddFriend(agreeID, 1);

	return RET_SUCCESS;
}

ProtoBuf::ERetCode RelationMgr::AddRelation(uint32_t groupIndex, CharIDType agreeID, CharIDType applyID)
{
	switch (groupIndex)
	{
	case GROUP_FRIEND:
		return AgreeAddFriend(agreeID, applyID);
	case GROUP_BLACK:
		return AddBlack(agreeID, applyID);
	case GROUP_HATE:
		return AddHateList(agreeID, applyID);
	default:
		break;
	}
	return RET_RELATION_APPLY_GROUP_ERROR;
}

ProtoBuf::ERetCode RelationMgr::NoArgeeRelation(uint32_t groupIndex, CharIDType agreeID, CharIDType applyID)
{
	OfflineCharacterData *pApplyOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(applyID);
	if (nullptr == pApplyOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	Relation* pAgreeRelation = FindRelation(agreeID);
	if (nullptr == pAgreeRelation)
	{
		return RET_FAIL;
	}

	Relation* pApplyRelation = FindRelation(applyID);
	if (nullptr == pApplyRelation)
	{
		return RET_FAIL;
	}

	//清除列表
	pAgreeRelation->DeleteApply(applyID);
	return RET_SUCCESS;
}

ProtoBuf::ERetCode RelationMgr::DeleteRelation(uint32_t groupIndex, CharIDType operateID, CharIDType deleteID)
{
	Relation* pOperateRelation = FindRelation(operateID);
	if (nullptr == pOperateRelation)
	{
		return RET_FAIL;
	}

	//为空可能删除角色了
	OfflineCharacterData *pDeleteOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(deleteID);
	if (nullptr == pDeleteOfflineCharacterData)
	{
		//这种情况直接删除好友
		pOperateRelation->DelUser(groupIndex, deleteID);
		return RET_NOT_HAVE_CHARACTER;
	}

	//异常情况也有直接删除
	Relation* pDeleteRelation = FindRelation(deleteID);
	if (nullptr == pDeleteRelation)
	{
		//这种情况直接删除好友
		pOperateRelation->DelUser(groupIndex, deleteID);
		return RET_FAIL;
	}

	//如果是删除好友先判断双方是否是好友关系
	if (groupIndex == GROUP_FRIEND)
	{
		//判断双方不是好友关系了
		if (!pOperateRelation->IsMyfriend(deleteID) || !pDeleteRelation->IsMyfriend(operateID))
		{
			return RET_RELATION_NOT_FRIENDS;
		}
	}

	//if (!pOperateRelation->DelUser(groupIndex, deleteID) || !pDeleteRelation->DelUser(groupIndex, operateID))
	//{
	//	return RET_FAIL;
	//}
	//直接删除
	pOperateRelation->DelUser(groupIndex, deleteID);
	pDeleteRelation->DelUser(groupIndex, operateID);

	return RET_SUCCESS;
}

ProtoBuf::ERetCode RelationMgr::GivePhyscial(CharIDType srcID, CharIDType dstID)
{
	OfflineCharacterData *pSrcOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(srcID);
	if (nullptr == pSrcOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	OfflineCharacterData *pDstOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(dstID);
	if (nullptr == pDstOfflineCharacterData)
	{
		return RET_NOT_HAVE_CHARACTER;
	}

	Relation* pSrcRelation = FindRelation(srcID);
	if (nullptr == pSrcRelation)
	{
		return RET_FAIL;
	}

	Relation* pDstRelation = FindRelation(dstID);
	if (nullptr == pDstRelation)
	{
		return RET_FAIL;
	}

	//判断双方是不是好友关系了
	if (!pSrcRelation->IsMyfriend(dstID) || !pDstRelation->IsMyfriend(srcID))
	{
		return RET_RELATION_NOT_FRIENDS;
	}
	
	ERetCode status = pSrcRelation->GivePhyscial(dstID);
	if (status != RET_SUCCESS)
	{
		return status;
	}

	return pDstRelation->SetGivePhyStatus(srcID);
}

ProtoBuf::ERetCode RelationMgr::GetPhyscial(CharIDType srcID, CharIDType dstID)
{
	OfflineCharacterData *pSrcOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(srcID);
	if (nullptr == pSrcOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	OfflineCharacterData *pDstOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(dstID);
	if (nullptr == pDstOfflineCharacterData)
	{
		return RET_NOT_HAVE_CHARACTER;
	}

	Relation* pSrcRelation = FindRelation(srcID);
	if (nullptr == pSrcRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::GetPhyscial but srcID pRelation is nullptr,srcID:%u ", srcID);
		return RET_FAIL;
	}

	Relation* pDstRelation = FindRelation(dstID);
	if (nullptr == pDstRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::GetPhyscial but dstID pRelation is nullptr,dstID:%u ", dstID);
		return RET_FAIL;
	}

	//判断双方是不是好友关系了
	if (!pSrcRelation->IsMyfriend(dstID) || !pDstRelation->IsMyfriend(srcID))
	{
		return RET_RELATION_NOT_FRIENDS;
	}

	ERetCode status = pSrcRelation->GetPhyscial(dstID);
	if (status == RET_SUCCESS)
	{
		//成功增加对方进度
		pDstRelation->AddGiftProgress(srcID);
	}

	return status;
}

ProtoBuf::ERetCode RelationMgr::GetRandomOnlineUserEx(CharIDType playerID, bool again, std::list<RecentPlayer>& ids)
{
	std::list<RecentPlayer> characterIDs;

	Relation* pSrcRelation = FindRelation(playerID);
	if (nullptr == pSrcRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::GetRandomOnlineUserEx but pSrcRelation is nullptr,playerID:%llu ", playerID);
		return RET_FAIL;
	}

	/*if (again && pSrcRelation->InCdTime())
	{
		return RET_RELATION_IN_CD_TIME;
	}*/

	//如果是第一次刷新，那么推荐最近给玩家
	Relation::RecentList& recentList = pSrcRelation->GetRecentList();
	if (!again)
	{
		ids = recentList;
	}

	//如果最近联系人大于50
	if (ids.size() >= MAX_RECENT_SIZE)
	{
		return RET_SUCCESS;
	}

	uint32_t count = MAX_RECENT_SIZE - ids.size();

	OfflineCharacterData *pSrcOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(playerID);
	if (nullptr == pSrcOfflineCharacterData)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::GetRandomOnlineUserEx but OfflineCharacterData is nullptr,playerID:%llu ", playerID);
		return RET_FAIL;
	}

	uint32_t onlineCount = g_GetActiveCharacterMgr()->GetOnlineNum();
	std::unordered_map<CharIDType, ActiveCharacter*> pActiveCharacterMap = g_GetActiveCharacterMgr()->GetOnlineCharacterMap();
	std::unordered_map<CharIDType, ActiveCharacter*>::iterator iter = pActiveCharacterMap.begin();
	if (onlineCount <= count)
	{
		for (; iter != pActiveCharacterMap.end(); ++iter)
		{
			if (playerID == iter->first)
			{
				continue;
			}

			Relation* pDstRelation = FindRelation(iter->first);
			if (nullptr == pDstRelation)
			{
				continue;
			}

			//判断双方是否是好友关系
			if (pSrcRelation->IsMyfriend(iter->first) || pDstRelation->IsMyfriend(playerID))
			{
				continue;
			}

			OfflineCharacterData *pDstOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(iter->first);
			if (nullptr == pDstOfflineCharacterData)
			{
				MMOLOG_FMT_ERROR("[center] RelationMgr::GetRandomOnlineUserEx but pDstOfflineCharacterData is nullptr,playerID:%llu ", iter->first);
				continue;
			}

			if (abs(pDstOfflineCharacterData->GetLevel() - pSrcOfflineCharacterData->GetLevel()) >= RELATION_LEVEL_INTERVAL)
			{
				continue;
			}

			//增加阵营判断
			//if (pDstOfflineCharacterData->GetCampID() != pSrcOfflineCharacterData->GetCampID())
			//{
			//	continue;
			//}

			//判断是否在最近联系人中了
			if (pSrcRelation->InRecentList(iter->first))
			{
				continue;
			}

			RecentPlayer recentPlayer;
			recentPlayer.id = iter->first;
			recentPlayer.recentType = RELATION_RECENT_SYSTEM;
			ids.push_back(recentPlayer);
		}

		return RET_SUCCESS;
	}

	//如果不小于
	for (; iter != pActiveCharacterMap.end(); ++iter)
	{
		if (playerID == iter->first)
		{
			continue;
		}

		Relation* pDstRelation = FindRelation(iter->first);
		if (nullptr == pDstRelation)
		{
			//MMOLOG_FMT_ERROR("[center] RelationMgr::GetRandomOnlineUserEx but pDstRelation is nullptr,playerID:%u ", iter->first);
			continue;
		}

		if (pSrcRelation->IsMyfriend(iter->first) || pDstRelation->IsMyfriend(playerID))
		{
			continue;
		}

		OfflineCharacterData *pDstOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(iter->first);
		if (nullptr == pDstOfflineCharacterData)
		{
			MMOLOG_FMT_ERROR("[center] RelationMgr::GetRandomOnlineUserEx but pDstOfflineCharacterData is nullptr,playerID:%llu ", iter->first);
			continue;
		}

		if (abs(pDstOfflineCharacterData->GetLevel() - pSrcOfflineCharacterData->GetLevel()) >= RELATION_LEVEL_INTERVAL)
		{
			continue;
		}

		//增加阵营判断
		//if (pDstOfflineCharacterData->GetCampID() != pSrcOfflineCharacterData->GetCampID())
		//{
		//	continue;
		//}

		//判断是否在最近联系人中了
		if (pSrcRelation->InRecentList(iter->first))
		{
			continue;
		}

		RecentPlayer recentPlayer;
		recentPlayer.id = iter->first;
		recentPlayer.recentType = RELATION_RECENT_SYSTEM;
		characterIDs.push_back(recentPlayer);
	}

	if (characterIDs.size() <= count)
	{
		for (std::list<RecentPlayer>::iterator it = characterIDs.begin(); it != characterIDs.end(); ++it)
		{
			ids.push_back(*it);
		}
		return RET_SUCCESS;
	}
	
	uint32_t num = 1;
	while (num <= count)
	{
		std::list<RecentPlayer>::iterator pIter = characterIDs.begin();
		uint32_t size = characterIDs.size();
		uint32_t randomNum = Random(size);
		advance(pIter, randomNum);
		ids.push_back(*pIter);
		characterIDs.erase(pIter);
		num++;
	}

	return RET_SUCCESS;
}

ProtoBuf::ERetCode RelationMgr::UpdateRecentList(CharIDType srcID, CharIDType dstID, uint32_t type)
{
	ProtoBuf::ERetCode ret = OperateCheck(srcID, dstID);
	if (RET_SUCCESS == ret)
	{
		Relation* pSrcRelation = FindRelation(srcID);
		if (nullptr == pSrcRelation)
		{
			return RET_FAIL;
		}

		Relation* pDstRelation = FindRelation(dstID);
		if (nullptr == pDstRelation)
		{
			return RET_FAIL;
		}

		pSrcRelation->UpdateRecentList(dstID, type);
		pDstRelation->UpdateRecentList(srcID, type);
	}
	else if (RET_RELATION_HAVE_NO_DATA == ret)
	{
		QueryRelationDB(srcID, dstID, RELATION_OPERATE_TYPE_RECENT, to_string(type));
	}

	return ret;
}

uint32_t RelationMgr::GetClosenessLv(CharIDType srcID, CharIDType dstID)
{
	if (IsFriendRelation(srcID, dstID))
	{
		Relation* pSrcRelation = FindRelation(srcID);
		if (nullptr == pSrcRelation)
		{
			return 0;
		}

		return pSrcRelation->GetClosenessLv(dstID);
	}

	return 0;
}

uint32_t RelationMgr::GetCloseness(CharIDType srcID, CharIDType dstID)
{
	if (IsFriendRelation(srcID, dstID))
	{
		Relation* pSrcRelation = FindRelation(srcID);
		if (nullptr == pSrcRelation)
		{
			return 0;
		}

		return pSrcRelation->GetCloseness(dstID);
	}

	return 0;
}

void RelationMgr::AddCloseness(CharIDType srcID, CharIDType dstID, uint32_t type, uint32_t value)
{
	if (IsFriendRelation(srcID, dstID))
	{
		Relation* pSrcRelation = FindRelation(srcID);
		if (nullptr != pSrcRelation)
		{
			pSrcRelation->AddCloseness(dstID, type, value);
			if (pSrcRelation->IsChange())
			{
				C2LUpdateCloseness updateCloseness;
				updateCloseness.set_charid(srcID);
				updateCloseness.set_value(pSrcRelation->GetCloseness(dstID));
				g_GetCenterService()->SendDataToLogicByCharID(srcID, EMODULE_ID_FRIEND, CENTER_TO_LOGIC_UPDATE_CLOSENESS, &updateCloseness);
			}
		}
	}
}

uint32_t RelationMgr::GetConfigClosenessLv(uint32_t closeness)
{
	//if (closeness <= 0)
	//{
	//	return 0;
	//}

	const FriendshipFriendshipCfgMap* pFriendShipCfg = g_GetFriendshipFriendshipCfgTable()->GetFriendshipFriendshipCfgMap();
	if (nullptr == pFriendShipCfg)
	{
		return 0;
	}

	for (FriendshipFriendshipCfgMap::const_iterator iter = pFriendShipCfg->begin(); iter != pFriendShipCfg->end(); ++iter)
	{
		if (closeness >= (uint32_t)iter->second.minIntimacy && closeness <= (uint32_t)iter->second.maxIntimacy)
		{
			return iter->second.id;
		}
	}

	return 0;
}

void RelationMgr::AddCharm(CharIDType charID, uint32_t value)
{
	OfflineCharacterData *pDstOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr != pDstOfflineCharacterData)
	{
		pDstOfflineCharacterData->SetCharm(pDstOfflineCharacterData->GetCharm() + value);
		C2LUpdateCharm c2lUpdateCharm;
		c2lUpdateCharm.set_charid(charID);
		c2lUpdateCharm.set_value(pDstOfflineCharacterData->GetCharm());
		g_GetCenterService()->SendDataToLogicByCharID(charID, EMODULE_ID_FRIEND, CENTER_TO_LOGIC_UPDATE_CHARM, &c2lUpdateCharm);
	}
}

inline bool total_charm_cmp(const RankingListCharmData &r1, const RankingListCharmData &r2)
{
	return r1.charm() > r2.charm();
}

inline bool week_charm_cmp(const RankingListCharmData &r1, const RankingListCharmData &r2)
{
	return r1.charm_week() > r2.charm_week();
}

void RelationMgr::GetCharmRank(std::vector<RankingListCharmData> &vec, int8_t rankType)
{
	RelationIter iter = _relationMap.begin();
	for (; iter != _relationMap.end(); ++iter)
	{
		Relation *pRelation = iter->second;
		if (nullptr == pRelation)
			continue;
		OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(iter->first);
		if (nullptr == pOffline)
			continue;

		RankingListCharmData charmData;
		charmData.set_username(pOffline->GetCharName());
		charmData.set_prof(pOffline->GetProf());
		charmData.set_charm(pOffline->GetCharm());
		charmData.set_charm_today(pRelation->GetCharmToday());
		charmData.set_charm_week(pRelation->GetCharmWeek());
		charmData.set_charm_lst_week(pRelation->GetCharmLstWeek());
		vec.push_back(charmData);
	}
	if (rankType == 1)
		sort(vec.begin(), vec.end(), total_charm_cmp);	//总榜
	if (rankType == 2)
		sort(vec.begin(), vec.end(), week_charm_cmp);	//周榜
	if (vec.size() > 100)
		vec.assign(vec.begin(), vec.begin() + 100);
}

void RelationMgr::CampChange(OfflineCharacterData* p)
{
	Relation* pRelation = FindRelation(p->GetCharID());
	if (nullptr == pRelation)
		return;

	Relation::GroupList groupList = pRelation->GetGroupList();
	RelationTeam::PlayerList& idList = groupList[GROUP_FRIEND].playerList;
	for (RelationTeam::PlayerListIter iter = idList.begin(); iter != idList.end(); ++iter)
	{
		CharIDType relationCharID = iter->id;
		ActiveCharacter* pActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(relationCharID);
		if (nullptr == pActiveCharacter)
			continue;

		W2CRelationCampUpdate campUpdate;
		campUpdate.set_charid(p->GetCharID());
		campUpdate.set_camp(p->GetCampID());
		g_GetCenterService()->SendDataToClient(relationCharID, EMODULE_ID_FRIEND, CENTER_TO_CLINET_UPDATE_CAMP, &campUpdate);
	}
}

void RelationMgr::GM_AddCloseness(CharIDType srcID, CharIDType dstID, uint32_t type, uint32_t value)
{
	AddCloseness(srcID, dstID, type, value);
	AddCloseness(dstID, srcID, type, value);
	g_GetTeamMgr()->TeamClosenessUpdate(srcID);
}

bool RelationMgr::IsFriendRelation(CharIDType srcID, CharIDType dstID)
{
	Relation* pSrcRelation = FindRelation(srcID);
	if (nullptr == pSrcRelation)
	{
		return false;
	}

	Relation* pDstRelation = FindRelation(dstID);
	if (nullptr == pDstRelation)
	{
		return false;
	}
	if (pSrcRelation->IsMyfriend(dstID) && pDstRelation->IsMyfriend(srcID))
	{
		return true;
	}

	return false;
}

bool RelationMgr::IsInBlack(CharIDType srcID, CharIDType dstID)
{
	Relation* pSrcRelation = FindRelation(srcID);
	if (nullptr == pSrcRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::IsInBlack but srcID pRelation is nullptr,srcID:%u ", srcID);
		return false;
	}

	return pSrcRelation->inBlack(dstID);
}

void RelationMgr::DeleteAllRelation(CharIDType srcID, CharIDType dstID)
{
	Relation* pSrcRelation = FindRelation(srcID);
	if (nullptr == pSrcRelation)
	{
		MMOLOG_FMT_ERROR("[center] RelationMgr::DeleteAllRelation but srcID pSrcRelation is nullptr,srcID:%u ", srcID);
		return;
	}

	pSrcRelation->DeleteRelation(dstID); //解除所有关系
}

void  RelationMgr::NotifyLogicAddFriend(CharIDType charId, uint32_t addNum)
{
	WGNotifyAddFriend notify;
	notify.set_charid(charId);
	notify.set_operate_type(1);
	notify.set_addnum(addNum);
	g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_FRIEND, CENTER_SERVER_PROTOCOL_ADD_FRIEND_NOTIFY, &notify);
}

ProtoBuf::ERetCode RelationMgr::AddHateList(CharIDType srcID, CharIDType dstID)
{
	OfflineCharacterData *pSrcOfflineCharacterData = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(srcID);
	if (nullptr == pSrcOfflineCharacterData)
	{
		return RET_DATA_ERROR;
	}

	ActiveCharacter* pDstActiveCharacter = g_GetActiveCharacterMgr()->GetOnlineCharacter(srcID);
	if (nullptr == pDstActiveCharacter)
	{
		return RET_PLAYER_NOT_ONLINE;
	}

	//切磋副本不加入仇恨列表
	dupInfo *pDupInfo = g_GetCenterDuplicateMgr()->getDuplicate(pDstActiveCharacter->GetSceneID());
	if (nullptr != pDupInfo && EDuplicateKeyType_Compete == pDupInfo->keyType)
	{
		return RET_FAIL;
	}

	Relation* pDstRelation = FindRelation(dstID);
	if (nullptr == pDstRelation)
	{
		return RET_FAIL;
	}

	Relation* pSrcRelation = FindRelation(srcID);
	if (nullptr == pSrcRelation)
	{
		return RET_FAIL;
	}

	//自己不能添加自己
	if (srcID == dstID)
	{
		return RET_FAIL;
	}

	if (pDstRelation->InHateList(srcID))
	{
		//击杀仇人
		WGNotifyAddFriend notify;
		notify.set_charid(dstID);
		notify.set_operate_type(2);
		g_GetCenterService()->SendDataToLogicByCharID(dstID, EMODULE_ID_FRIEND, CENTER_SERVER_PROTOCOL_ADD_FRIEND_NOTIFY, &notify);
	}

	//如果已经在仇恨列表中了 返回错误出去 外部通过错误不用再推送一次信息给玩家
	if (pSrcRelation->InHateList(dstID))
	{
		pSrcRelation->AddUser(GROUP_HATE, dstID);
		return RET_FAIL;
	}

	//添加近仇恨列表
	pSrcRelation->AddUser(GROUP_HATE, dstID);
	return RET_SUCCESS;
}

void RelationMgr::LoadList(RelationTeam::PlayerList& idList, VEC_UINT64 &list)
{
	for (RelationTeam::PlayerListIter iter = idList.begin(); iter != idList.end(); ++iter)
	{
		CharIDType relationCharID = iter->id;
		Relation* pFRelation = FindRelation(relationCharID);
		if (nullptr == pFRelation)
		{
			list.push_back(relationCharID);
		}
	}
}

void RelationMgr::LoadList(ProtoBuf::CWDeleteRelationReq &deleteReq, VEC_UINT64 &list)
{
	for (int i = 0; i < deleteReq.playeridlist_size(); i++)
	{
		CharIDType dstID = deleteReq.playeridlist(i);
		Relation* pFRelation = FindRelation(dstID);
		if (nullptr == pFRelation)
		{
			list.push_back(dstID);
		}
	}
}

void RelationMgr::LoadList(ProtoBuf::CWAllGivePhyscialReq &giveReq, VEC_UINT64 &list)
{
	for (int i = 0; i < giveReq.playerids_size(); i++)
	{
		CharIDType dstID = giveReq.playerids(i);
		Relation* pFRelation = FindRelation(dstID);
		if (nullptr == pFRelation)
		{
			list.push_back(dstID);
		}
	}
}

void RelationMgr::LoadList(Relation::ApplyIDList applyIdList, VEC_UINT64 &list)
{
	for (Relation::ApplyIDListpIter iter = applyIdList.begin(); iter != applyIdList.end(); ++iter)
	{
		CharIDType applyID = *iter;
		Relation* pFRelation = FindRelation(applyID);
		if (nullptr == pFRelation)
		{
			list.push_back(applyID);
		}
	}
}
